Compare commits
81 Commits
setting-up
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 80070d4198 | |||
|
|
d54b643378 | ||
| a7ab058d01 | |||
|
|
903da29fed | ||
| d7f79c51c3 | |||
| 9b425229d3 | |||
|
|
f9328bdecb | ||
|
|
2e7105a18e | ||
| 758e033870 | |||
|
|
4d3d7a55e2 | ||
| 050a8f81fd | |||
| 766ed0ae65 | |||
|
|
6c496d644b | ||
|
|
515134dde5 | ||
| 8f365557a8 | |||
| 53a7248ea4 | |||
|
|
99b9df5066 | ||
|
|
3248359726 | ||
|
|
5296edc4a7 | ||
| 01f27bf6f9 | |||
|
|
367b5d51f2 | ||
| e47336dc8d | |||
|
|
4767756499 | ||
| b9fb75ff36 | |||
|
|
72ccd5e71c | ||
|
|
75692d7b20 | ||
| 06aec8c900 | |||
|
|
d40b225e4e | ||
|
|
6892c56c1e | ||
|
|
fd880aeaa2 | ||
| 2c267b71e4 | |||
|
|
2e60460131 | ||
|
|
44efa194fc | ||
|
|
5b1acd1c5f | ||
|
|
3ff212d6d2 | ||
|
|
7c3407c86d | ||
| 3cff15ed25 | |||
|
|
abe79e5556 | ||
|
|
00d15ebe7e | ||
|
|
533451f39d | ||
|
|
d01c1a0232 | ||
|
|
7369739bdd | ||
|
|
d3011d77ff | ||
| 598f706958 | |||
|
|
314abe0462 | ||
|
|
f32b5d5748 | ||
| eb924d2bec | |||
|
|
2cfac4a023 | ||
|
|
7df0c64d15 | ||
| 8a2dbfe055 | |||
|
|
60042ebd30 | ||
|
|
937c61c635 | ||
|
|
7320fcb527 | ||
| 3b7ba95d27 | |||
|
|
045d349c86 | ||
| 04df3ece96 | |||
|
|
4779c32a56 | ||
|
|
85e695b2d8 | ||
|
|
c2d6923375 | ||
| f4dcb823c4 | |||
| 080587f327 | |||
| 0b8792b373 | |||
| 11d560f4d2 | |||
|
|
499906f883 | ||
|
|
0a450eae56 | ||
|
|
56bb362e51 | ||
|
|
dc728c4183 | ||
|
|
1f30f85787 | ||
| 9750aa2c37 | |||
|
|
aefa8d927b | ||
| faea7f213b | |||
|
|
dcf1652dd9 | ||
|
|
1353404aed | ||
|
|
386f051d67 | ||
| 32c0cd1ffc | |||
|
|
67615d76dd | ||
| f52d8d9a30 | |||
|
|
203961986d | ||
| a4fed06efc | |||
|
|
0829e049f0 | ||
| 5fa6f33501 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
backend
|
||||
debug
|
||||
.vscode
|
||||
.vs/
|
||||
|
||||
23
Dockerfile
Normal file
23
Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
||||
# Builder image
|
||||
FROM --platform=linux/amd64 golang:1.21 as builder
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
RUN go build -mod=readonly -v -o pactual-backend main.go
|
||||
|
||||
# Runtime image
|
||||
FROM --platform=linux/amd64 golang:1.21
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the binary from the builder stage
|
||||
COPY --from=builder /src/pactual-backend .
|
||||
|
||||
# Copy the app/views/qor folder
|
||||
COPY app/views/qor /app/app/views/qor
|
||||
|
||||
CMD ["/app/pactual-backend"]
|
||||
@@ -20,11 +20,14 @@ func Load() error {
|
||||
}
|
||||
|
||||
AppConfig = Config{
|
||||
|
||||
|
||||
Service: Service{
|
||||
// 9000 DEFAULT FOR DEV ENVIRONMENT
|
||||
Port: getEnv("NOVATECH_SERVICE_PORT", "9000"),
|
||||
Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"),
|
||||
Port: getEnv("NOVATECH_SERVICE_PORT", "9000"),
|
||||
Environment: getEnv("NOVATECH_SERVICE_ENVIRONMENT", "DEV"),
|
||||
MapboxAccessToken: getEnv("NOVATECH_SERVICE_MAPBOX_ACCESS_TOKEN", ""),
|
||||
JwtSecretKey: getEnv("JWT_SECRET_KEY", "MDQsCiJwYWNrZXRWZXJzaW9uIjogMSwKImhhcm"),
|
||||
JwtSecretKeyExpiryHours: getEnv("JWT_SECRET_KEY_EXPIRY_HOURS", "24"),
|
||||
},
|
||||
AdminService: Service{
|
||||
// 8080 DEFAULT FOR DEV ENVIRONMENT
|
||||
@@ -32,14 +35,22 @@ func Load() error {
|
||||
Environment: getEnv("NOVATECH_ADMIN_SERVICE_ENVIRONMENT", "DEV"),
|
||||
},
|
||||
Database: Database{
|
||||
UserName: mustGetEnv("NOVATECH_DATABASE_USERNAME"),
|
||||
Password: mustGetEnv("NOVATECH_DATABASE_PASSWORD"),
|
||||
DatabaseName: mustGetEnv("NOVATECH_DATABASE_NAME"),
|
||||
HostName: mustGetEnv("NOVATECH_DATABASE_ADDRESS"),
|
||||
Port: mustGetEnv("NOVATECH_DATABASE_PORT"),
|
||||
|
||||
UserName: getEnv("NOVATECH_DATABASE_USERNAME", "username"),
|
||||
Password: getEnv("NOVATECH_DATABASE_PASSWORD", "password"),
|
||||
DatabaseName: getEnv("NOVATECH_DATABASE_NAME", "dbname"),
|
||||
HostName: getEnv("NOVATECH_DATABASE_ADDRESS", "localhost"),
|
||||
Port: getEnv("NOVATECH_DATABASE_PORT", "5432"),
|
||||
},
|
||||
Blockchain: Blockchain{
|
||||
NetworkEndpoint: getEnv("NOVATECH_BLOCKCHAIN_NETWORK_ENDPOINT", ""),
|
||||
ContractAddress: getEnv("NOVATECH_BLOCKCHAIN_CONTRACT_ADDRESS", ""),
|
||||
WalletAddress: getEnv("NOVATECH_BLOCKCHAIN_WALLET_ADDRESS", ""),
|
||||
WalletPrivateKey: getEnv("NOVATECH_BLOCKCHAIN_WALLET_PRIVATE_KEY", ""),
|
||||
},
|
||||
AWS: AWS{
|
||||
AccessKey: getEnv("AWS_ACCESS_KEY_ID", ""),
|
||||
SecretKey: getEnv("AWS_SECRET_ACCESS_KEY", ""),
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -2,25 +2,41 @@ package config
|
||||
|
||||
// Config stores application configuration
|
||||
type Config struct {
|
||||
Service Service
|
||||
AdminService Service
|
||||
Database Database
|
||||
Service Service
|
||||
AdminService Service
|
||||
Database Database
|
||||
Blockchain Blockchain
|
||||
AWS AWS
|
||||
}
|
||||
|
||||
|
||||
// Service contains configuration for service
|
||||
type Service struct {
|
||||
Port string
|
||||
Environment string
|
||||
WebPageURL string
|
||||
Port string
|
||||
Environment string
|
||||
WebPageURL string
|
||||
MapboxAccessToken string
|
||||
JwtSecretKey string
|
||||
JwtSecretKeyExpiryHours string
|
||||
}
|
||||
|
||||
// Blockchain contains configuration for blockchain
|
||||
type Blockchain struct {
|
||||
NetworkEndpoint string
|
||||
ContractAddress string
|
||||
WalletAddress string
|
||||
WalletPrivateKey string
|
||||
}
|
||||
|
||||
// Database configuration
|
||||
type Database struct {
|
||||
UserName string
|
||||
Password string
|
||||
DatabaseName string
|
||||
HostName string
|
||||
Port string
|
||||
UserName string
|
||||
Password string
|
||||
DatabaseName string
|
||||
HostName string
|
||||
Port string
|
||||
}
|
||||
|
||||
type AWS struct {
|
||||
AccessKey string
|
||||
SecretKey string
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Created by VoidArtanis on 11/2/2017
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/VoidArtanis/go-rest-boilerplate/middlewares"
|
||||
"github.com/VoidArtanis/go-rest-boilerplate/shared"
|
||||
)
|
||||
|
||||
type AuthController struct{}
|
||||
|
||||
|
||||
func (this AuthController)HandleLogin(c *gin.Context) {
|
||||
userId:="123"
|
||||
username:="Beast"
|
||||
roles:= []string{shared.RoleAdmin, shared.RoleProUser}
|
||||
|
||||
// do user auth here
|
||||
|
||||
//issue token
|
||||
token, err := middlewares.GenerateToken([]byte(middlewares.SigningKey), userId,username, roles)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
c.JSON(200, token)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package controllers
|
||||
|
||||
// import (
|
||||
// "net/http"
|
||||
// models "novatech/models"
|
||||
|
||||
// "github.com/VoidArtanis/go-rest-boilerplate/models"
|
||||
// "github.com/gin-gonic/gin"
|
||||
// )
|
||||
|
||||
// func Companies(c *gin.Context) {
|
||||
// var companies []models.Company
|
||||
// // Fetch companies from DB here
|
||||
// if err := models.FetchCompanies(&companies); err != nil {
|
||||
// c.JSON(http.StatusInternalServerError, gin.H{"error": "Error fetching companies"})
|
||||
// return
|
||||
// }
|
||||
// c.JSON(http.StatusOK, gin.H{"companies": companies})
|
||||
// }
|
||||
31
controllers/auth_controller.go
Normal file
31
controllers/auth_controller.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"gitlab.com/pactual1/backend/middlewares"
|
||||
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AuthController struct{}
|
||||
|
||||
func (AuthController) HandleLogin(c *gin.Context) {
|
||||
userId := "123"
|
||||
username := "Beast"
|
||||
roles := []string{shared.RoleAdmin, shared.RoleProUser}
|
||||
|
||||
// do user auth here
|
||||
|
||||
//issue token
|
||||
token, err := middlewares.GenerateToken([]byte(middlewares.SigningKey), userId, username, roles)
|
||||
if err != nil {
|
||||
log.Printf("Unable to generate token %v", err)
|
||||
c.JSON(http.StatusInternalServerError, err)
|
||||
|
||||
}
|
||||
c.JSON(200, token)
|
||||
}
|
||||
81
controllers/companies_controller.go
Normal file
81
controllers/companies_controller.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/pactual1/backend/database/company"
|
||||
)
|
||||
|
||||
func ListCompanies(c *gin.Context) {
|
||||
// Get limit and offset from query parameter with defaults
|
||||
limitStr := c.DefaultQuery("limit", "50")
|
||||
offsetStr := c.DefaultQuery("offset", "0")
|
||||
iDsStr := c.QueryArray("ids[]")
|
||||
|
||||
// Convert limit and offset to int
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
log.Printf("ListCompanies Error: Invalid limit value: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"})
|
||||
return
|
||||
}
|
||||
|
||||
offset, err := strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
log.Printf("ListCompanies Error: Invalid offset value: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset value"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert ids to []int64
|
||||
var companyIDs []int64
|
||||
for _, idStr := range iDsStr {
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id value"})
|
||||
return
|
||||
}
|
||||
companyIDs = append(companyIDs, id)
|
||||
}
|
||||
|
||||
// Fetch companies
|
||||
companies, total, st, err := company.GetCompanies(companyIDs, limit, offset)
|
||||
if err != nil {
|
||||
c.JSON(st, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the companies and the total count
|
||||
c.JSON(http.StatusOK, gin.H{"total": total, "data": companies})
|
||||
}
|
||||
|
||||
func GetCompanyByID(c *gin.Context) {
|
||||
// Get the company ID from url parameters
|
||||
companyIDStr := c.Param("company_id")
|
||||
|
||||
if companyIDStr == "" {
|
||||
log.Printf("GetCompanyByID Error: ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
companyID, err := strconv.ParseUint(companyIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetCompanyByID Error: Invalid ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch company
|
||||
companies, _, st, err := company.GetCompanies([]int64{int64(companyID)}, 1, 0)
|
||||
if err != nil {
|
||||
c.JSON(st, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the companies and the total count
|
||||
c.JSON(http.StatusOK, gin.H{"data": companies[0]})
|
||||
}
|
||||
26
controllers/companies_controller_test.go
Normal file
26
controllers/companies_controller_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package controllers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func TestListCompanies(t *testing.T) {
|
||||
ts := runTestServer()
|
||||
defer ts.Close()
|
||||
defer shared.CloseDb()
|
||||
|
||||
t.Run("it should return 200", func(t *testing.T) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/buyers?limit=20", ts.URL))
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
398
controllers/contracts_controller.go
Normal file
398
controllers/contracts_controller.go
Normal file
@@ -0,0 +1,398 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gitlab.com/pactual1/backend/database/contract"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
const (
|
||||
BlockchainSecretLength = 16
|
||||
)
|
||||
|
||||
func GetLatestContracts(c *gin.Context) {
|
||||
// Existing parameters
|
||||
limitStr := c.DefaultQuery("limit", "50")
|
||||
offsetStr := c.DefaultQuery("offset", "0")
|
||||
status := strings.Split(c.DefaultQuery("status", models.ContractStatusActive), ",")
|
||||
|
||||
// New/Updated optional parameters
|
||||
companyName := c.Query("company_name")
|
||||
companyAddress := c.Query("company_address")
|
||||
companyEmail := c.Query("company_email")
|
||||
companyPhone := c.Query("company_phone")
|
||||
contractName := c.Query("contract_name")
|
||||
startTimeStr := c.Query("start_time")
|
||||
endTimeStr := c.Query("end_time")
|
||||
deviceIDsStr := c.QueryArray("deviceIDs[]")
|
||||
iDsStr := c.QueryArray("ids[]")
|
||||
|
||||
company := c.GetInt("companyID")
|
||||
uuid := c.Query("uuid")
|
||||
|
||||
// Convert limit and offset to int
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"})
|
||||
return
|
||||
}
|
||||
|
||||
offset, err := strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset value"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert startTime to time.Time
|
||||
var startTime time.Time
|
||||
if startTimeStr != "" {
|
||||
startTimeUnix, err := strconv.ParseInt(startTimeStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid start_time value"})
|
||||
return
|
||||
}
|
||||
startTime = time.Unix(startTimeUnix, 0)
|
||||
}
|
||||
|
||||
// Convert endTime to time.Time
|
||||
var endTime time.Time
|
||||
if endTimeStr != "" {
|
||||
endTimeUnix, err := strconv.ParseInt(endTimeStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid end_time value"})
|
||||
return
|
||||
}
|
||||
endTime = time.Unix(endTimeUnix, 0)
|
||||
}
|
||||
|
||||
// Convert deviceIDs to []int64
|
||||
var deviceIDs []int64
|
||||
for _, idStr := range deviceIDsStr {
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid deviceID value"})
|
||||
return
|
||||
}
|
||||
deviceIDs = append(deviceIDs, id)
|
||||
}
|
||||
|
||||
// Convert ids to []int64
|
||||
var contractIDs []int64
|
||||
for _, idStr := range iDsStr {
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id value"})
|
||||
return
|
||||
}
|
||||
contractIDs = append(contractIDs, id)
|
||||
}
|
||||
|
||||
// Fetch contracts
|
||||
contracts, total, st, err := contract.GetContracts(status, companyName, companyAddress, companyEmail, companyPhone, &startTime, &endTime, contractName, deviceIDs, contractIDs, nil, uuid, company, 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, "data": models.ConvertContractToDashboardResponse(contracts)})
|
||||
}
|
||||
|
||||
func GetBuyerContracts(c *gin.Context) {
|
||||
// Existing parameters
|
||||
limitStr := c.DefaultQuery("limit", "50")
|
||||
offsetStr := c.DefaultQuery("offset", "0")
|
||||
status := c.QueryArray("status")
|
||||
iDsStr := c.QueryArray("ids[]")
|
||||
qStr := c.Query("q")
|
||||
dateCreatedStr := c.Query("date_created")
|
||||
startTimeStr := c.Query("start_time")
|
||||
endTimeStr := c.Query("end_time")
|
||||
company := c.GetInt("companyID")
|
||||
|
||||
// Convert limit and offset to int
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"})
|
||||
return
|
||||
}
|
||||
|
||||
offset, err := strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset value"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert startTime to time.Time
|
||||
var startTime *time.Time
|
||||
if startTimeStr != "" {
|
||||
startTimeUnix, err := strconv.ParseInt(startTimeStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid start_time value"})
|
||||
return
|
||||
}
|
||||
startTimeValue := time.Unix(startTimeUnix, 0)
|
||||
startTime = &startTimeValue
|
||||
}
|
||||
|
||||
// Convert endTime to time.Time
|
||||
var endTime *time.Time
|
||||
if endTimeStr != "" {
|
||||
endTimeUnix, err := strconv.ParseInt(endTimeStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid end_time value"})
|
||||
return
|
||||
}
|
||||
endTimeValue := time.Unix(endTimeUnix, 0)
|
||||
endTime = &endTimeValue
|
||||
}
|
||||
|
||||
// Convert startTime to time.Time
|
||||
var dateCreated time.Time
|
||||
if dateCreatedStr != "" {
|
||||
startTimeUnix, err := strconv.ParseInt(dateCreatedStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid start_time value"})
|
||||
return
|
||||
}
|
||||
dateCreated = time.Unix(startTimeUnix, 0)
|
||||
}
|
||||
|
||||
// Convert ids to []int64
|
||||
var contractIDs []int64
|
||||
for _, idStr := range iDsStr {
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id value"})
|
||||
return
|
||||
}
|
||||
contractIDs = append(contractIDs, id)
|
||||
}
|
||||
|
||||
// Fetch contracts
|
||||
contracts, total, st, err := contract.GetContracts(status, "", "", "", "", startTime, endTime, qStr, nil, contractIDs, &dateCreated, "", company, 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, "data": models.ConvertContractToListResponse(contracts)})
|
||||
}
|
||||
|
||||
func GetContractStatuses(c *gin.Context) {
|
||||
|
||||
// Respond with the contract statuses
|
||||
c.JSON(http.StatusOK, gin.H{"data": models.GetContractStatuses()})
|
||||
}
|
||||
|
||||
func CreateContract(c *gin.Context) {
|
||||
|
||||
var payload models.CreateContractRequestPayload
|
||||
|
||||
if err := c.ShouldBindJSON(&payload); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON payload"})
|
||||
log.Printf("Invalid JSON payload: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
db := shared.GetDb()
|
||||
|
||||
newContract := models.Contract{
|
||||
UUID: uuid.New().String(),
|
||||
BuyerID: payload.BuyerID,
|
||||
SellerID: payload.SellerID,
|
||||
Description: payload.Description,
|
||||
ProductID: payload.ProductID,
|
||||
MinTemp: payload.MinTemp,
|
||||
MaxTemp: payload.MaxTemp,
|
||||
ArrivalDate: time.Unix(payload.ArrivalDate, 0),
|
||||
PenaltyType: payload.PenaltyType,
|
||||
PenaltyValue: payload.PenaltyValue,
|
||||
PenaltyRec: payload.PenaltyRec,
|
||||
StartLat: payload.StartLat,
|
||||
StartLon: payload.StartLon,
|
||||
Status: models.ContractStatusPending,
|
||||
StartPlaceName: payload.StartPlaceName,
|
||||
EndPlaceName: payload.EndPlaceName,
|
||||
Name: payload.Name,
|
||||
EndLat: payload.EndLat,
|
||||
EndLon: payload.EndLon,
|
||||
BlockchainSecret: shared.GenerateRandomString(BlockchainSecretLength),
|
||||
}
|
||||
|
||||
if err := db.Create(&newContract).Error; err != nil {
|
||||
log.Printf("SaveContractInfo CREATE - Contract DB Error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not create new contract"})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Successfully received and saved contract: %v", newContract)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Successfully received and saved contract", "id": newContract.ID})
|
||||
}
|
||||
|
||||
func GetContractByID(c *gin.Context) {
|
||||
// Get the contract ID from url parameters
|
||||
contractIDStr := c.Param("contract_id")
|
||||
|
||||
if contractIDStr == "" {
|
||||
log.Printf("GetContractByID Error: ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
contractID, err := strconv.ParseUint(contractIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetContractByID Error: Invalid ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch contract
|
||||
contract, st, err := contract.GetContractByID(uint(contractID), "")
|
||||
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{"data": models.ConvertContractToContractResponse(contract)})
|
||||
}
|
||||
|
||||
func UpdateContract(c *gin.Context) {
|
||||
|
||||
var contractModel models.Contract
|
||||
rawData, _ := c.GetRawData()
|
||||
|
||||
// Unmarshal to the important info structure
|
||||
err := json.Unmarshal(rawData, &contractModel)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON payload"})
|
||||
log.Printf("Invalid json pyload : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the contract ID from url parameters
|
||||
contractIDStr := c.Param("contract_id")
|
||||
if contractIDStr == "" {
|
||||
log.Printf("UpdateContract Error: ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
contractID, err := strconv.ParseUint(contractIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("UpdateContract Error: Invalid ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
contractModel.ID = uint(contractID)
|
||||
|
||||
// update contract
|
||||
contractModel, st, err := contract.UpdateContract(contractModel)
|
||||
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{"data": models.ConvertContractToContractResponse(contractModel)})
|
||||
}
|
||||
|
||||
func GetContractCountByStatus(c *gin.Context) {
|
||||
companyID := c.DefaultQuery("company_id", "")
|
||||
startTimeStr := c.DefaultQuery("start_time", "")
|
||||
endTimeStr := c.DefaultQuery("end_time", "")
|
||||
|
||||
if companyID == "" || startTimeStr == "" || endTimeStr == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Missing required query parameters",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to uint and time.Time
|
||||
companyIDUint, err := strconv.ParseUint(companyID, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Invalid companyID",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to Unix timestamp
|
||||
startUnix, err := strconv.ParseInt(startTimeStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Invalid start time",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
endUnix, err := strconv.ParseInt(endTimeStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Invalid end time",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert Unix timestamps to time.Time
|
||||
startTime := time.Unix(startUnix, 0)
|
||||
endTime := time.Unix(endUnix, 0)
|
||||
|
||||
activeCount, executedCount, _, monthly, err := contract.CountContractsByMultipleStatusesAndTotal(uint(companyIDUint), startTime, endTime)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Internal Server Error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": models.ActiveContractsResponse{ActiveCount: activeCount, ExecutedCount: executedCount, MonthlyContracts: monthly}})
|
||||
|
||||
}
|
||||
|
||||
func GetTotalContractCount(c *gin.Context) {
|
||||
companyID := c.DefaultQuery("company_id", "0")
|
||||
startTimeStr := c.DefaultQuery("start_time", "")
|
||||
endTimeStr := c.DefaultQuery("end_time", "")
|
||||
|
||||
// Convert to uint and time.Time
|
||||
companyIDUint, err := strconv.ParseUint(companyID, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Invalid companyID",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to Unix timestamp
|
||||
startUnix, _ := strconv.ParseInt(startTimeStr, 10, 64)
|
||||
endUnix, _ := strconv.ParseInt(endTimeStr, 10, 64)
|
||||
|
||||
// Convert Unix timestamps to time.Time
|
||||
startTime := time.Unix(startUnix, 0)
|
||||
endTime := time.Unix(endUnix, 0)
|
||||
|
||||
_, _, totalCount, _, err := contract.CountContractsByMultipleStatusesAndTotal(uint(companyIDUint), startTime, endTime)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Internal Server Error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": totalCount})
|
||||
}
|
||||
299
controllers/devices_controller.go
Normal file
299
controllers/devices_controller.go
Normal file
@@ -0,0 +1,299 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/database/contract"
|
||||
"gitlab.com/pactual1/backend/database/device"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/services/blockchain"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
const (
|
||||
ContractDistanceThresholdKm = float64(10)
|
||||
)
|
||||
|
||||
func SaveDeviceInfo(c *gin.Context) {
|
||||
var deviceInfo models.DeviceInfo
|
||||
rawData, _ := c.GetRawData()
|
||||
|
||||
// Unmarshal to the important info structure
|
||||
err := json.Unmarshal(rawData, &deviceInfo)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON payload"})
|
||||
log.Printf("Invalid json payload : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
deviceInfo, currentDevice, err := device.SaveDeviceInfoToDB(deviceInfo, rawData)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if currentDevice.CurrentContractID != nil {
|
||||
deviceContract, _, err := contract.GetContractByID(*currentDevice.CurrentContractID, "")
|
||||
if err != nil {
|
||||
log.Printf("SaveDeviceInfo - GetContractByID error : %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not fetch device contract"})
|
||||
return
|
||||
}
|
||||
|
||||
if deviceContract.Status == models.ContractStatusActive {
|
||||
deviceInfoBytes, _ := json.Marshal(deviceInfo)
|
||||
if deviceContract.BlockchainSecret == "" {
|
||||
deviceContract.BlockchainSecret = shared.GenerateRandomString(BlockchainSecretLength)
|
||||
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"})
|
||||
return
|
||||
}
|
||||
}
|
||||
deviceInfoEncryptedStr, err := shared.NewEncryptionClient(deviceContract.BlockchainSecret).Encrypt(string(deviceInfoBytes))
|
||||
if err != nil {
|
||||
log.Printf("SaveDeviceInfo - Enrypt error : %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not encrypt device info"})
|
||||
return
|
||||
}
|
||||
|
||||
err = blockchain.NewService(config.AppConfig.Blockchain).AddIOTData(context.Background(), shared.CovertUintToByte32(deviceContract.ID), shared.CovertUintToByte32(currentDevice.ID), big.NewInt(time.Now().Unix()), []byte(deviceInfoEncryptedStr))
|
||||
if err != nil {
|
||||
log.Printf("SaveDeviceInfo CREATE -DeviceInfo Blockchain Error: %v", err)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Successfully received and saved device info: %v", deviceInfo)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Successfully received and saved device info", "data": deviceInfo})
|
||||
}
|
||||
|
||||
func GetDeviceData(c *gin.Context) {
|
||||
// Get the device ID and contract ID from query parameters
|
||||
deviceIDStr := c.DefaultQuery("device_id", "")
|
||||
contractIDStr := c.DefaultQuery("contract_id", "")
|
||||
|
||||
uuid := c.DefaultQuery("uuid", "")
|
||||
|
||||
if deviceIDStr == "" {
|
||||
log.Printf("GetDeviceData Error: Device ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Device ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
deviceID, err := strconv.ParseUint(deviceIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetDeviceData Error: Invalid Device ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Device ID"})
|
||||
return
|
||||
}
|
||||
|
||||
contractID, err := strconv.ParseUint(contractIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetDeviceData Error: Invalid Contract ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Contract ID"})
|
||||
return
|
||||
}
|
||||
|
||||
contract, st, err := contract.GetContractByID(uint(contractID), uuid) // Update this line to pass UUID
|
||||
if err != nil {
|
||||
c.JSON(st, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
deviceConnectedToContract := false
|
||||
for _, contractDeviceID := range contract.DeviceIDs {
|
||||
if deviceID == uint64(contractDeviceID) {
|
||||
deviceConnectedToContract = true
|
||||
}
|
||||
}
|
||||
|
||||
if !deviceConnectedToContract {
|
||||
log.Printf("Device %v is not connected to contract %v", deviceID, contractID)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Device is not present int his contract"})
|
||||
return
|
||||
}
|
||||
|
||||
featureCollection, st, err := device.GetDeviceInfoForContract(deviceID, contract)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(st, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the GeoJSON feature collection
|
||||
c.JSON(http.StatusOK, gin.H{"data": featureCollection})
|
||||
}
|
||||
|
||||
func GetDevicesByContract(c *gin.Context) {
|
||||
// Get the contract ID and UUID from query parameters
|
||||
contractIDStr := c.DefaultQuery("contract_id", "")
|
||||
uuid := c.DefaultQuery("uuid", "") // Add this line to get the UUID
|
||||
|
||||
if contractIDStr == "" {
|
||||
log.Printf("GetDevicesByContract Error: Contract ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Contract ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
companyID := c.GetInt("companyID")
|
||||
|
||||
// Convert string to uint
|
||||
contractID, err := strconv.ParseUint(contractIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetDevicesByContract Error: Invalid Contract ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Contract ID"})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("This is the Contract ID: %v, UUID: %s", contractID, uuid)
|
||||
devices, st, err := device.GetDevicesForContract(contractID, uuid, companyID) // Pass UUID here
|
||||
|
||||
if err != nil {
|
||||
c.JSON(st, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the devices
|
||||
c.JSON(http.StatusOK, gin.H{"data": models.ConvertDeviceToResponse(devices)})
|
||||
}
|
||||
|
||||
func GetCompanyRelatedDeviceInfoCount(c *gin.Context) {
|
||||
// Get the Company ID from query parameters
|
||||
companyIDStr := c.DefaultQuery("company_id", "")
|
||||
if companyIDStr == "" {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: Company ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Company ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to uint for CompanyID
|
||||
companyID, err := strconv.ParseUint(companyIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: Invalid Company ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Company ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Perform the counting
|
||||
count, err := device.CountDeviceInfoByCompany(uint(companyID))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the count
|
||||
c.JSON(http.StatusOK, gin.H{"data": count})
|
||||
}
|
||||
|
||||
func GetCompanyRelatedDeviceInfoCountWithTempRange(c *gin.Context) {
|
||||
// Get the Company ID from query parameters
|
||||
companyIDStr := c.DefaultQuery("company_id", "")
|
||||
startTimeStr := c.DefaultQuery("start_time", "")
|
||||
endTimeStr := c.DefaultQuery("end_time", "")
|
||||
if companyIDStr == "" {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: Company ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Company ID is required"})
|
||||
return
|
||||
}
|
||||
if startTimeStr == "" {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: startTime ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Start time is required"})
|
||||
return
|
||||
}
|
||||
|
||||
if endTimeStr == "" {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: endTime is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "End time is required"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to Unix timestamp
|
||||
startUnix, _ := strconv.ParseInt(startTimeStr, 10, 64)
|
||||
endUnix, _ := strconv.ParseInt(endTimeStr, 10, 64)
|
||||
|
||||
// Convert Unix timestamps to time.Time
|
||||
startTime := time.Unix(startUnix, 0)
|
||||
endTime := time.Unix(endUnix, 0)
|
||||
|
||||
// Convert string to uint for CompanyID
|
||||
companyID, err := strconv.ParseUint(companyIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: Invalid Company ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Company ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get the counts
|
||||
inRangeCount, outOfRangeCount, monthlyCount, err := device.CountDeviceBreachedAndNormalDevicesByCompany(uint(companyID), startTime, endTime)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
data := models.NormalAndBreachedDevicesResponse{Breached: outOfRangeCount, Normal: inRangeCount, MonthlyCounts: monthlyCount}
|
||||
|
||||
// Respond with both counts
|
||||
c.JSON(http.StatusOK, gin.H{"data": data})
|
||||
}
|
||||
|
||||
func GetContractsMatchingDeviceLocation(c *gin.Context) {
|
||||
startTimeStr := c.DefaultQuery("start_time", "")
|
||||
endTimeStr := c.DefaultQuery("end_time", "")
|
||||
companyIDStr := c.DefaultQuery("company_id", "")
|
||||
|
||||
if companyIDStr == "" {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: Company ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Company ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to uint for CompanyID
|
||||
companyID, err := strconv.ParseUint(companyIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetCompanyRelatedDeviceInfoCount Error: Invalid Company ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Company ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to Unix timestamp
|
||||
startUnix, _ := strconv.ParseInt(startTimeStr, 10, 64)
|
||||
endUnix, _ := strconv.ParseInt(endTimeStr, 10, 64)
|
||||
|
||||
// Convert Unix timestamps to time.Time
|
||||
startTime := time.Unix(startUnix, 0)
|
||||
endTime := time.Unix(endUnix, 0)
|
||||
|
||||
matches, err := device.FetchMatchingContractsAndDeviceInfo(companyID, startTime, endTime)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Internal Server Error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": len(matches),
|
||||
})
|
||||
}
|
||||
83
controllers/devices_controller_test.go
Normal file
83
controllers/devices_controller_test.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package controllers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/controllers"
|
||||
"gitlab.com/pactual1/backend/routes"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
// Assume setupServer() returns your gin.Engine instance
|
||||
func runTestServer() *httptest.Server {
|
||||
// Initialize your database or any other setup
|
||||
// For the sake of this example, I'll just return the Gin engine
|
||||
|
||||
// LOAD APPLICATION CONFIGURATION
|
||||
err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
shared.Init()
|
||||
r := gin.Default()
|
||||
r.POST("/device_info", controllers.SaveDeviceInfo)
|
||||
routes.RegisterPublicRoutes(r)
|
||||
return httptest.NewServer(r)
|
||||
}
|
||||
|
||||
func TestSaveDeviceInfofunc(t *testing.T) {
|
||||
ts := runTestServer()
|
||||
defer ts.Close()
|
||||
defer shared.CloseDb()
|
||||
|
||||
t.Run("it should return 400 when JSON payload is invalid", func(t *testing.T) {
|
||||
payload := []byte(`{"InvalidPayload": `)
|
||||
resp, err := http.Post(fmt.Sprintf("%s/device_info", ts.URL), "application/json", bytes.NewBuffer(payload))
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 400, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("it should log a message when IMEI is not found", func(t *testing.T) {
|
||||
// Add a valid payload but with an unknown IMEI
|
||||
payload := []byte(`{"IMEI": "UNKNOWN", "SomeOtherField": "Value"}`)
|
||||
resp, err := http.Post(fmt.Sprintf("%s/device_info", ts.URL), "application/json", bytes.NewBuffer(payload))
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("it should return 200 when all conditions are correct", func(t *testing.T) {
|
||||
// Add a valid payload
|
||||
deviceInfo := map[string]interface{}{
|
||||
"IMEI": "SOME_VALID_IMEI",
|
||||
"SomeOtherField": "Value",
|
||||
}
|
||||
|
||||
payload, _ := json.Marshal(deviceInfo)
|
||||
resp, err := http.Post(fmt.Sprintf("%s/device_info", ts.URL), "application/json", bytes.NewBuffer(payload))
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
11
controllers/health_controller.go
Normal file
11
controllers/health_controller.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func HealthCheck(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"health": "ready"})
|
||||
}
|
||||
144
controllers/invoices_controller.go
Normal file
144
controllers/invoices_controller.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/pactual1/backend/database/invoice"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
)
|
||||
|
||||
func GetInvoices(c *gin.Context) {
|
||||
limitStr := c.DefaultQuery("limit", "10")
|
||||
offsetStr := c.DefaultQuery("offset", "0")
|
||||
buyerName := c.Query("buyer_name")
|
||||
sortBy := c.Query("sort_by")
|
||||
iDsStr := c.QueryArray("ids[]")
|
||||
status := c.QueryArray("status")
|
||||
companyID := c.GetInt("companyID")
|
||||
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"})
|
||||
return
|
||||
}
|
||||
|
||||
offset, err := strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset value"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert ids to []int64
|
||||
var invoiceIDs []int64
|
||||
for _, idStr := range iDsStr {
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id value"})
|
||||
return
|
||||
}
|
||||
invoiceIDs = append(invoiceIDs, id)
|
||||
}
|
||||
|
||||
invoices, total, err := invoice.GetInvoices(buyerName, sortBy, limit, offset, invoiceIDs, status, companyID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to ListInvoiceResponse type
|
||||
listInvoiceResponses := convertToResponseModel(invoices)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"total": total, "data": listInvoiceResponses})
|
||||
}
|
||||
|
||||
func GetInvoiceByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
|
||||
return
|
||||
}
|
||||
|
||||
companyID := c.GetInt("companyID")
|
||||
|
||||
invoices, _, err := invoice.GetInvoices("", "", 1, 0, []int64{int64(id)}, nil, companyID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
invoiceResponses := models.ConvertInvoiceToResponse(invoices)
|
||||
|
||||
if len(invoices) > 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"data": invoiceResponses[0]})
|
||||
} else {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Invoice not found"})
|
||||
}
|
||||
}
|
||||
|
||||
func convertToResponseModel(invoices []models.Invoice) []models.ListInvoiceResponse {
|
||||
listInvoiceResponses := []models.ListInvoiceResponse{}
|
||||
|
||||
// Get all statuses
|
||||
statuses := models.GetInvoiceStatuses()
|
||||
statusMap := make(map[string]models.Status)
|
||||
for _, s := range statuses {
|
||||
statusMap[s.Value] = s
|
||||
}
|
||||
|
||||
for _, invoice := range invoices {
|
||||
// Get the status based on Value in the DB
|
||||
status, ok := statusMap[invoice.Status]
|
||||
if !ok {
|
||||
status = models.Status{Key: "Unknown", Value: "unknown"}
|
||||
}
|
||||
|
||||
listInvoiceResponse := models.ListInvoiceResponse{
|
||||
Status: models.KeyValue{Key: status.Key, Value: status.Value},
|
||||
Buyer: models.CompanyShortResponse{ID: int(invoice.BuyerID), Name: invoice.BuyerName},
|
||||
ContractID: int(invoice.ContractID),
|
||||
DateCreated: invoice.InvoiceDate,
|
||||
DueDate: invoice.InvoiceDueDate,
|
||||
Amount: strconv.FormatInt(invoice.PriceCents, 10),
|
||||
}
|
||||
listInvoiceResponses = append(listInvoiceResponses, listInvoiceResponse)
|
||||
}
|
||||
return listInvoiceResponses
|
||||
}
|
||||
|
||||
func GetInvoiceCountByStatus(c *gin.Context) {
|
||||
companyID := c.DefaultQuery("company_id", "0")
|
||||
startTimeStr := c.DefaultQuery("start_time", "")
|
||||
endTimeStr := c.DefaultQuery("end_time", "")
|
||||
|
||||
// Convert to uint and time.Time
|
||||
companyIDUint, err := strconv.ParseUint(companyID, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Invalid companyID",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to Unix timestamp
|
||||
startUnix, _ := strconv.ParseInt(startTimeStr, 10, 64)
|
||||
endUnix, _ := strconv.ParseInt(endTimeStr, 10, 64)
|
||||
|
||||
// Convert Unix timestamps to time.Time
|
||||
startTime := time.Unix(startUnix, 0)
|
||||
endTime := time.Unix(endUnix, 0)
|
||||
|
||||
activeCount, executedCount, monthly, err := invoice.CountInvoicesByMultipleStatuses(uint(companyIDUint), startTime, endTime)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Internal Server Error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": models.ActiveInvoiceResponse{Claimed: activeCount, Issued: executedCount, MonthlyInvoices: monthly}})
|
||||
|
||||
}
|
||||
32
controllers/locations_controller.go
Normal file
32
controllers/locations_controller.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/services/location"
|
||||
)
|
||||
|
||||
func SearchPlace(c *gin.Context) {
|
||||
query := c.Query("q")
|
||||
|
||||
if query == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "query is empty"})
|
||||
return
|
||||
}
|
||||
|
||||
mapboxAccessToken := config.AppConfig.Service.MapboxAccessToken
|
||||
locationClient := location.NewService(mapboxAccessToken)
|
||||
|
||||
places, err := locationClient.SearchPlace(c, query)
|
||||
if err != nil {
|
||||
log.Printf("SearchPlace Error: Service error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Service error"})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the buyers and the total count
|
||||
c.JSON(http.StatusOK, gin.H{"data": places})
|
||||
}
|
||||
50
controllers/notifications_controller.go
Normal file
50
controllers/notifications_controller.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/pactual1/backend/database/notification"
|
||||
)
|
||||
|
||||
func GetNotifications(c *gin.Context) {
|
||||
// Get the Company ID and Time from query parameters
|
||||
companyIDStr := c.DefaultQuery("company_id", "")
|
||||
timeStr := c.DefaultQuery("time", "")
|
||||
|
||||
if companyIDStr == "" || timeStr == "" {
|
||||
log.Printf("GetNotifications Error: Company ID and Time are required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Company ID and Time are required"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert string to int for UserID
|
||||
userID, err := strconv.Atoi(companyIDStr)
|
||||
if err != nil {
|
||||
log.Printf("GetNotifications Error: Invalid Company ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid User ID"})
|
||||
return
|
||||
}
|
||||
|
||||
timestamp, err := strconv.ParseInt(timeStr, 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("GetNotifications Error: afterTime parameter ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "After time parameter ID"})
|
||||
return
|
||||
}
|
||||
afterTime := time.Unix(timestamp, 0)
|
||||
|
||||
log.Printf("This is the Company ID: %v and Time: %v", userID, afterTime)
|
||||
notifications, st, err := notification.GetNotificationsForCompanyID(userID, afterTime)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(st, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the notifications
|
||||
c.JSON(http.StatusOK, gin.H{"data": notifications})
|
||||
}
|
||||
115
controllers/product_templates_controller.go
Normal file
115
controllers/product_templates_controller.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func ListProductTemplates(c *gin.Context) {
|
||||
// Get limit and offset from query parameter with defaults
|
||||
limitStr := c.DefaultQuery("limit", "50")
|
||||
offsetStr := c.DefaultQuery("offset", "0")
|
||||
iDsStr := c.QueryArray("ids[]")
|
||||
|
||||
// Convert limit and offset to int
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
log.Printf("ListProductTemplates Error: Invalid limit value: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"})
|
||||
return
|
||||
}
|
||||
|
||||
offset, err := strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
log.Printf("ListProductTemplates Error: Invalid offset value: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset value"})
|
||||
return
|
||||
}
|
||||
|
||||
// Create a slice to hold the product templates
|
||||
productTemplates := []models.ProductTemplate{}
|
||||
|
||||
// Convert ids to []int64
|
||||
var productIDs []int64
|
||||
for _, idStr := range iDsStr {
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id value"})
|
||||
return
|
||||
}
|
||||
productIDs = append(productIDs, id)
|
||||
}
|
||||
|
||||
countDb := shared.GetDb()
|
||||
db := shared.GetDb()
|
||||
if len(productIDs) > 0 {
|
||||
countDb = countDb.Where("id IN (?)", productIDs)
|
||||
db = db.Where("id IN (?)", productIDs)
|
||||
}
|
||||
|
||||
// Count the total number of product templates
|
||||
var total int64
|
||||
if err := countDb.Model(&models.ProductTemplate{}).Count(&total).Error; err != nil {
|
||||
log.Printf("ListProductTemplates Error: Database error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch the product templates from the database with LIMIT and OFFSET
|
||||
if err := db.Order("created_at desc").Limit(limit).Offset(offset).Find(&productTemplates).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Printf("ListProductTemplates Error: No product templates found: %v", err)
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "No product templates found"})
|
||||
} else {
|
||||
log.Printf("ListProductTemplates Error: Database error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the product templates and the total count
|
||||
c.JSON(http.StatusOK, gin.H{"total": total, "data": productTemplates})
|
||||
}
|
||||
|
||||
func GetProductTemplate(c *gin.Context) {
|
||||
// Get the product template ID from query parameters
|
||||
productTemplateIDStr := c.Param("template_id")
|
||||
|
||||
if productTemplateIDStr == "" {
|
||||
log.Printf("GetProductTemplate Error: Product Template ID is required")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Product Template ID is required"})
|
||||
return
|
||||
}
|
||||
|
||||
productTemplateID, err := strconv.ParseUint(productTemplateIDStr, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("GetProductTemplate Error: Invalid Product Template ID: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Product Template ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch the product template
|
||||
var productTemplate models.ProductTemplate
|
||||
if err := shared.GetDb().Where("id = ?", productTemplateID).First(&productTemplate).Error; err != nil {
|
||||
log.Printf("GetProductTemplate Error: Could not fetch product template: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not fetch product template"})
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(productTemplate.Config), &productTemplate.ProductTemplateConfig)
|
||||
if err != nil {
|
||||
log.Printf("GetProductTemplate Error: Could not fetch product template config: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not fetch product template config"})
|
||||
return
|
||||
}
|
||||
// Respond with the product template
|
||||
c.JSON(http.StatusOK, productTemplate)
|
||||
}
|
||||
26
controllers/product_templates_controller_test.go
Normal file
26
controllers/product_templates_controller_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package controllers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func TestListProductTemplates(t *testing.T) {
|
||||
ts := runTestServer()
|
||||
defer ts.Close()
|
||||
defer shared.CloseDb()
|
||||
|
||||
t.Run("it should return 200", func(t *testing.T) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/products?limit=20", ts.URL))
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
@@ -6,10 +6,10 @@ package controllers
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func GetSecretText(c *gin.Context){
|
||||
func GetSecretText(c *gin.Context) {
|
||||
c.JSON(200, "Hi this is a secret message. Auth was successful!")
|
||||
}
|
||||
|
||||
func GetPublicText(c *gin.Context){
|
||||
func GetPublicText(c *gin.Context) {
|
||||
c.JSON(200, "Hi this is a public message!")
|
||||
}
|
||||
102
controllers/text_templates_controller.go
Normal file
102
controllers/text_templates_controller.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func ListTextTemplates(c *gin.Context) {
|
||||
// Get limit and offset from query parameter with defaults
|
||||
limitStr := c.DefaultQuery("limit", "50")
|
||||
offsetStr := c.DefaultQuery("offset", "0")
|
||||
iDsStr := c.QueryArray("ids[]")
|
||||
|
||||
// Convert limit and offset to int
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
log.Printf("ListTextTemplates Error: Invalid limit value: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"})
|
||||
return
|
||||
}
|
||||
|
||||
offset, err := strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
log.Printf("ListTextTemplates Error: Invalid offset value: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset value"})
|
||||
return
|
||||
}
|
||||
|
||||
// Convert ids to []int64
|
||||
var templateIDs []int64
|
||||
for _, idStr := range iDsStr {
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id value"})
|
||||
return
|
||||
}
|
||||
templateIDs = append(templateIDs, id)
|
||||
}
|
||||
|
||||
// Create a slice to hold the text templates
|
||||
textTemplates := []models.TextTemplate{}
|
||||
|
||||
// Count the total number of text templates
|
||||
var total int64
|
||||
countDb := shared.GetDb()
|
||||
db := shared.GetDb()
|
||||
if len(templateIDs) > 0 {
|
||||
countDb = countDb.Where("id IN (?)", templateIDs)
|
||||
db = db.Where("id IN (?)", templateIDs)
|
||||
}
|
||||
if err := countDb.Model(&models.TextTemplate{}).Count(&total).Error; err != nil {
|
||||
log.Printf("ListTextTemplates Error: Database error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch the text templates from the database with LIMIT and OFFSET
|
||||
if err := db.Order("created_at desc").Limit(limit).Offset(offset).Find(&textTemplates).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Printf("ListTextTemplates Error: No text templates found: %v", err)
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "No text templates found"})
|
||||
} else {
|
||||
log.Printf("ListTextTemplates Error: Database error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the text templates and the total count
|
||||
c.JSON(http.StatusOK, gin.H{"total": total, "data": textTemplates})
|
||||
}
|
||||
|
||||
func CreateTextTemplate(c *gin.Context) {
|
||||
var textTemplate models.TextTemplate
|
||||
rawData, _ := c.GetRawData()
|
||||
|
||||
// Unmarshal to the important info structure
|
||||
err := json.Unmarshal(rawData, &textTemplate)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON payload"})
|
||||
log.Printf("Invalid json pyload : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Save text template to your database
|
||||
if err := shared.GetDb().Create(&textTemplate).Error; err != nil {
|
||||
log.Printf("CreateTextTemplate DB Error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not create text template"})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Successfully received and saved text template: %v", textTemplate)
|
||||
c.JSON(http.StatusOK, gin.H{"data": textTemplate})
|
||||
}
|
||||
50
controllers/text_templates_controller_test.go
Normal file
50
controllers/text_templates_controller_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package controllers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func TestListTextTemplates(t *testing.T) {
|
||||
ts := runTestServer()
|
||||
defer ts.Close()
|
||||
defer shared.CloseDb()
|
||||
|
||||
t.Run("it should return 200", func(t *testing.T) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/templates?limit=20", ts.URL))
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func CreateTextTemplate(t *testing.T) {
|
||||
ts := runTestServer()
|
||||
defer ts.Close()
|
||||
defer shared.CloseDb()
|
||||
|
||||
t.Run("it should return 200", func(t *testing.T) {
|
||||
// Add a new text template
|
||||
data := map[string]interface{}{
|
||||
"Value": "text",
|
||||
}
|
||||
|
||||
payload, _ := json.Marshal(data)
|
||||
resp, err := http.Post(fmt.Sprintf("%s/templates/save", ts.URL), "application/json", bytes.NewBuffer(payload))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
})
|
||||
}
|
||||
178
controllers/users_controller.go
Normal file
178
controllers/users_controller.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/pactual1/backend/database/user"
|
||||
usr "gitlab.com/pactual1/backend/database/user"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/services/messaging"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func ResetPassword(c *gin.Context) {
|
||||
var req models.ResetPasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
dbUser, err := user.GetUserByEmail(req.Email)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
||||
return
|
||||
}
|
||||
|
||||
resetToken, err := GenerateResetToken()
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
err = user.SaveResetTokenToDB(dbUser.ID, resetToken)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
subject := "Password Reset Request"
|
||||
body := "Here is your password reset link: https://pactualdev.com/setNewPassword?token=" + resetToken
|
||||
email := models.EmailNotification{Body: body, Subject: subject, Email: dbUser.Email}
|
||||
|
||||
go func(email models.EmailNotification) {
|
||||
|
||||
emailChannel := messaging.GetEmailChannel()
|
||||
emailChannel <- email
|
||||
|
||||
}(email)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Reset email sent"})
|
||||
}
|
||||
|
||||
func GenerateResetToken() (string, error) {
|
||||
// Generate 32 random bytes (256 bits)
|
||||
randomBytes := make([]byte, 32)
|
||||
_, err := rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
return "", err // return an error if there was one
|
||||
}
|
||||
|
||||
// Encode the random bytes into a URL-safe base64 string
|
||||
resetToken := base64.URLEncoding.EncodeToString(randomBytes)
|
||||
|
||||
return resetToken, nil
|
||||
}
|
||||
|
||||
func UpdatePassword(c *gin.Context) {
|
||||
var req models.UpdatePasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Find the PasswordTokens entry
|
||||
var passwordToken models.PasswordTokens
|
||||
if err := shared.GetDb().Where("token = ?", req.Token).First(&passwordToken).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Invalid token"})
|
||||
return
|
||||
}
|
||||
|
||||
// Find the associated User
|
||||
var user models.User
|
||||
if err := shared.GetDb().Where("id = ?", passwordToken.UserID).First(&user).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// Hash the password before saving it
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Update the user's password and set them as active
|
||||
user.Password = string(hashedPassword)
|
||||
user.IsActive = true
|
||||
if err := shared.GetDb().Save(&user).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete the PasswordTokens entry
|
||||
if err := shared.GetDb().Delete(&passwordToken).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Password updated successfully"})
|
||||
}
|
||||
|
||||
func Login(c *gin.Context) {
|
||||
var req models.LoginRequest
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Bad request"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := usr.GetUserByEmail(req.Email)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
|
||||
return
|
||||
}
|
||||
|
||||
if usr.CheckPassword(user.Password, req.Password) {
|
||||
if user.IsActive && user.LoginAttempts < 10 {
|
||||
// Proceed with creating JWT token and resetting login attempts
|
||||
log.Printf("Companies length %v", len(user.Companies))
|
||||
if len(user.Companies) == 0 {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "User is not connected to a company"})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := usr.CreateSessionToken(user.ID, user.Companies[0].ID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not create JWT token"})
|
||||
return
|
||||
}
|
||||
|
||||
usr.ResetLoginAttempts(*user)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"token": token})
|
||||
} else {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Account locked or too many attempts"})
|
||||
}
|
||||
} else {
|
||||
// Wrong password, increment login attempts
|
||||
usr.IncrementLoginAttempts(*user)
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
|
||||
}
|
||||
}
|
||||
|
||||
func Logout(c *gin.Context) {
|
||||
// Extract the token from the request, typically from the Authorization header
|
||||
tokenString := c.GetHeader("Authorization")
|
||||
|
||||
// If using a Bearer token, strip the 'Bearer ' prefix
|
||||
if len(tokenString) > 7 && strings.ToUpper(tokenString[0:7]) == "BEARER " {
|
||||
tokenString = tokenString[7:]
|
||||
}
|
||||
|
||||
// Invalidate the session token
|
||||
err := usr.InvalidateSessionToken(tokenString)
|
||||
if err != nil {
|
||||
// Handle error, could be not found or database error
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unable to logout"})
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with success
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Successfully logged out"})
|
||||
}
|
||||
48
database/company/company.go
Normal file
48
database/company/company.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package company
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func GetCompanies(companyIDs []int64, limit, offset int) ([]models.Company, int64, int, error) {
|
||||
|
||||
companies := []models.Company{}
|
||||
db := shared.GetDb()
|
||||
countDb := db
|
||||
|
||||
// Search by IDs
|
||||
if len(companyIDs) > 0 {
|
||||
db = db.Where("companies.id IN (?)", companyIDs)
|
||||
countDb = countDb.Where("companies.id IN (?)", companyIDs)
|
||||
}
|
||||
|
||||
// Fetch total count of filtered records
|
||||
var total int64
|
||||
if err := countDb.Model(&models.Company{}).Count(&total).Error; err != nil {
|
||||
log.Printf("GetCompanies Error: Database error: %v", err)
|
||||
return companies, total, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
// Fetch companies with custom fields
|
||||
if err := db.Select("*").
|
||||
Order("created_at desc").
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&companies).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Printf("GetCompanies Error: No companies found: %v", err)
|
||||
return companies, total, http.StatusNotFound, err
|
||||
} else {
|
||||
log.Printf("GetCompanies Error: Database error: %v", err)
|
||||
return companies, total, http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
|
||||
return companies, total, http.StatusOK, nil
|
||||
}
|
||||
366
database/contract/contract.go
Normal file
366
database/contract/contract.go
Normal file
@@ -0,0 +1,366 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/lib/pq"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"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"
|
||||
)
|
||||
|
||||
func GetContracts(status []string, companyName string, companyAddress string, companyEmail string, companyPhone string,
|
||||
startTime *time.Time, endTime *time.Time, contractName string, deviceIDs []int64, contractIDs []int64, dateCreated *time.Time,
|
||||
uuid string, company, limit, offset int) ([]models.Contract, int64, int, error) {
|
||||
|
||||
var contracts []models.Contract
|
||||
db := shared.GetDb()
|
||||
countDb := db
|
||||
|
||||
customFields := "distinct contracts.*, array_length(contracts.device_ids, 1) as number_of_devices, " +
|
||||
"(SELECT array_agg(devices.imei) FROM devices WHERE devices.id = ANY(contracts.device_ids)) as devices_imeis_scanner"
|
||||
|
||||
// Search by Statuses
|
||||
if len(status) > 0 {
|
||||
db = db.Where("contracts.status IN (?)", status)
|
||||
countDb = countDb.Where("contracts.status IN (?)", status)
|
||||
}
|
||||
|
||||
// Search by IDs
|
||||
if len(contractIDs) > 0 {
|
||||
db = db.Where("contracts.id IN (?)", contractIDs)
|
||||
countDb = countDb.Where("contracts.id IN (?)", contractIDs)
|
||||
}
|
||||
|
||||
// Search by Company Fields
|
||||
db = db.Joins("left join companies on companies.id = contracts.buyer_id")
|
||||
countDb = countDb.Joins("left join companies on companies.id = contracts.buyer_id")
|
||||
customFields += ", companies.name as buyer_name"
|
||||
if companyName != "" {
|
||||
db = db.Where("companies.name LIKE ?", "%"+companyName+"%")
|
||||
countDb = countDb.Where("companies.name LIKE ?", "%"+companyName+"%")
|
||||
}
|
||||
if companyAddress != "" {
|
||||
db = db.Where("companies.address LIKE ?", "%"+companyAddress+"%")
|
||||
countDb = countDb.Where("companies.address LIKE ?", "%"+companyAddress+"%")
|
||||
}
|
||||
if companyEmail != "" {
|
||||
db = db.Where("companies.email LIKE ?", "%"+companyEmail+"%")
|
||||
countDb = countDb.Where("companies.email LIKE ?", "%"+companyEmail+"%")
|
||||
}
|
||||
if companyPhone != "" {
|
||||
db = db.Where("companies.phone LIKE ?", "%"+companyPhone+"%")
|
||||
countDb = countDb.Where("companies.phone LIKE ?", "%"+companyPhone+"%")
|
||||
}
|
||||
|
||||
// Search by Contract Name
|
||||
if contractName != "" {
|
||||
db = db.Where("lower(contracts.name) LIKE ?", "%"+strings.ToLower(contractName)+"%")
|
||||
countDb = countDb.Where("lower(contracts.name) LIKE ?", "%"+strings.ToLower(contractName)+"%")
|
||||
}
|
||||
|
||||
// Check if uuid is present
|
||||
if uuid != "" {
|
||||
db = db.Where("contracts.uuid = ?", uuid)
|
||||
countDb = countDb.Where("contracts.uuid = ?", uuid)
|
||||
}
|
||||
|
||||
// Search by Start Time and End Time
|
||||
if startTime != nil && !startTime.IsZero() {
|
||||
db = db.Where("start_time >= ?", startTime)
|
||||
countDb = countDb.Where("start_time >= ?", startTime)
|
||||
}
|
||||
|
||||
if endTime != nil && !startTime.IsZero() {
|
||||
db = db.Where("end_time <= ?", endTime)
|
||||
countDb = countDb.Where("end_time <= ?", endTime)
|
||||
}
|
||||
|
||||
if dateCreated != nil && !dateCreated.IsZero() {
|
||||
db = db.Where("contracts.created_at = ?", dateCreated)
|
||||
countDb = countDb.Where("contracts.created_at = ?", dateCreated)
|
||||
}
|
||||
|
||||
// Search by Device IDs
|
||||
if len(deviceIDs) > 0 {
|
||||
db = db.Where("contracts.device_ids && ?", pq.Array(deviceIDs))
|
||||
countDb = countDb.Where("contracts.device_ids && ?", pq.Array(deviceIDs))
|
||||
}
|
||||
|
||||
// Fetch total count of filtered records
|
||||
var total int64
|
||||
if err := countDb.Model(&models.Contract{}).Count(&total).Error; err != nil {
|
||||
log.Printf("GetContracts Error: Database error: %v", err)
|
||||
return contracts, total, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
// Fetch contracts with custom fields
|
||||
if err := db.Select(customFields).
|
||||
Order("created_at desc").
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&contracts).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Printf("GetContracts Error: No contracts found: %v", err)
|
||||
return contracts, total, http.StatusNotFound, err
|
||||
} else {
|
||||
log.Printf("GetContracts Error: Database error: %v", err)
|
||||
return contracts, total, http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
for i := range contracts {
|
||||
contracts[i].DevicesImeis = []string(contracts[i].DevicesImeisScanner)
|
||||
// Now DevicesImeis contains the IMEIs, and you can use them as needed
|
||||
}
|
||||
|
||||
return contracts, total, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func UpdateContract(contract models.Contract) (models.Contract, int, error) {
|
||||
var devices []models.Device
|
||||
var status int
|
||||
var err error
|
||||
if contract.DevicesImeis != nil {
|
||||
log.Printf("Found devices imes %v", contract.DevicesImeis)
|
||||
devices, status, err = device.GetDevicesByImei(contract.DevicesImeis)
|
||||
if err != nil {
|
||||
return contract, status, err
|
||||
}
|
||||
|
||||
status, err = validateContractDevices(contract.ID, devices)
|
||||
if err != nil {
|
||||
log.Printf("UpdateContract Error: Invalid Device ID: %v", err)
|
||||
return contract, status, err
|
||||
}
|
||||
}
|
||||
|
||||
// get old contract to compare updates
|
||||
oldContract, status, err := GetContractByID(contract.ID, "")
|
||||
if err != nil {
|
||||
return contract, status, err
|
||||
}
|
||||
|
||||
err = shared.GetDb().Transaction(func(tx *gorm.DB) error {
|
||||
// Update contract
|
||||
if err := tx.Model(contract).Updates(contract).Error; err != nil {
|
||||
log.Printf("UpdateContract Error: Could not update contract: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if devices != nil {
|
||||
// Update devices
|
||||
if err := tx.Model(models.Device{}).Where("id IN (?)", []int64(contract.DeviceIDs)).Updates(models.Device{CurrentContractID: &contract.ID}).Error; err != nil {
|
||||
log.Printf("UpdateContract Error: Could not update devices: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// return nil will commit the whole transaction
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("UpdateContract Error: Could not update contract: %v", err)
|
||||
return contract, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
contract, status, err = GetContractByID(contract.ID, "")
|
||||
if err != nil {
|
||||
return contract, status, err
|
||||
}
|
||||
|
||||
// Create contract in blockchain only when it is signed
|
||||
if oldContract.Status != contract.Status {
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
func validateContractDevices(contractID uint, devices []models.Device) (int, error) {
|
||||
|
||||
for _, device := range devices {
|
||||
if device.CurrentContractID != nil && *device.CurrentContractID != contractID {
|
||||
currentDeviceContract, status, err := GetContractByID(*device.CurrentContractID, "")
|
||||
if err != nil {
|
||||
return status, err
|
||||
}
|
||||
|
||||
if currentDeviceContract.Status != models.ContractStatusExecuted &&
|
||||
currentDeviceContract.Status == models.ContractStatusRevoked {
|
||||
return http.StatusBadRequest, fmt.Errorf("device id %d is linked to contract id - %d name %s", device.ID, currentDeviceContract.ID, currentDeviceContract.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return http.StatusOK, nil
|
||||
}
|
||||
|
||||
func GetContractByID(contractID uint, uuid string) (models.Contract, int, error) {
|
||||
|
||||
var contract models.Contract
|
||||
db := shared.GetDb().Unscoped().Where("id = ?", contractID)
|
||||
|
||||
// Include UUID in the query if provided
|
||||
if uuid != "" {
|
||||
db = db.Where("uuid = ?", uuid)
|
||||
}
|
||||
|
||||
if err := db.First(&contract).Error; err != nil {
|
||||
log.Printf("GetContractByID Error: Could not fetch contract: %v", err)
|
||||
return contract, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
// Fetch the product
|
||||
var product models.ProductTemplate
|
||||
if err := shared.GetDb().Unscoped().Where("id = ?", contract.ProductID).First(&product).Error; err != nil {
|
||||
log.Printf("GetContractByID Error: Could not fetch product: %v", err)
|
||||
return contract, http.StatusInternalServerError, err
|
||||
}
|
||||
contract.ProductName = product.Name
|
||||
|
||||
// Fetch the seller
|
||||
var seller models.Company
|
||||
if err := shared.GetDb().Unscoped().Where("id = ?", contract.SellerID).First(&seller).Error; err != nil {
|
||||
log.Printf("GetContractByID Error: Could not fetch seller: %v", err)
|
||||
return contract, http.StatusInternalServerError, err
|
||||
}
|
||||
contract.SellerName = seller.Name
|
||||
|
||||
// Fetch the buyer
|
||||
var buyer models.Company
|
||||
if err := shared.GetDb().Unscoped().Where("id = ?", contract.BuyerID).First(&buyer).Error; err != nil {
|
||||
log.Printf("GetContractByID Error: Could not fetch buyer: %v", err)
|
||||
return contract, http.StatusInternalServerError, err
|
||||
}
|
||||
contract.BuyerName = buyer.Name
|
||||
|
||||
// Fetch the devices
|
||||
// Convert DeviceIDs from pq.Int64Array to []int64 for the query
|
||||
deviceIDs := make([]int64, 0, len(contract.DeviceIDs))
|
||||
for _, id := range contract.DeviceIDs {
|
||||
deviceIDs = append(deviceIDs, int64(id))
|
||||
}
|
||||
|
||||
// Fetch the devices using the slice of device IDs
|
||||
var devicesInfo []models.ContractDeviceInfo
|
||||
if err := shared.GetDb().
|
||||
Table("devices"). // Specify the actual table name for devices
|
||||
Where("id IN (?)", deviceIDs).
|
||||
Select("id, imei").
|
||||
Find(&devicesInfo).Error; err != nil {
|
||||
log.Printf("GetContractByID Error: Could not fetch devices: %v", err)
|
||||
return contract, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
// Prepare a slice of IMEIs to add to the contract
|
||||
deviceImeis := make([]string, len(devicesInfo))
|
||||
for i, device := range devicesInfo {
|
||||
deviceImeis[i] = device.IMEI
|
||||
}
|
||||
|
||||
contract.DevicesImeis = deviceImeis
|
||||
|
||||
return contract, http.StatusOK, nil
|
||||
}
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
// 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 '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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
return activeCount, executedCount, totalCount, monthlyCounts, nil
|
||||
}
|
||||
351
database/device/device.go
Normal file
351
database/device/device.go
Normal file
@@ -0,0 +1,351 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/services/messaging"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func GetDevicesForContract(contractID uint64, uuid string, companyID int) ([]models.Device, int, error) {
|
||||
// Fetch the contract from the database using both contractID and UUID
|
||||
var contract models.Contract
|
||||
query := shared.GetDb().Where("id = ?", contractID)
|
||||
|
||||
// If UUID is provided, include it in the query
|
||||
if uuid != "" {
|
||||
query = query.Where("uuid = ?", uuid)
|
||||
}
|
||||
|
||||
if err := query.First(&contract).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Printf("GetDevicesForContract Error: No contract found: %v", err)
|
||||
return nil, http.StatusNotFound, err
|
||||
} else {
|
||||
log.Printf("GetDevicesForContract Error: Database error: %v", err)
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("This is the device IDs: %v", contract.DeviceIDs)
|
||||
return GetDevicesByID(contract.DeviceIDs)
|
||||
}
|
||||
|
||||
func GetDevicesByID(deviceIDs []int64) ([]models.Device, int, error) {
|
||||
// Create a slice to hold the devices
|
||||
var devices []models.Device
|
||||
|
||||
// Convert the integer array to a comma-separated string
|
||||
idStrings := []string{}
|
||||
for _, id := range 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 GetDevicesByImei(imeiIDs []string) ([]models.Device, int, error) {
|
||||
// Create a slice to hold the devices
|
||||
var devices []models.Device
|
||||
|
||||
// Quote each IMEI ID
|
||||
for i, imei := range imeiIDs {
|
||||
imeiIDs[i] = "'" + imei + "'"
|
||||
}
|
||||
|
||||
// Join the quoted IMEI IDs into a comma-separated string
|
||||
idStr := strings.Join(imeiIDs, ",")
|
||||
|
||||
// Construct the SQL query manually
|
||||
sqlQuery := fmt.Sprintf("SELECT * FROM devices WHERE imei 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
|
||||
}
|
||||
}
|
||||
|
||||
deviceInfosResponse := models.ConvertDeviceInfoToResponse(deviceInfos)
|
||||
|
||||
// Loop through each deviceInfo to create GeoJSON features
|
||||
for _, info := range deviceInfosResponse {
|
||||
info.RawJSON = ""
|
||||
feature := models.GeoJSONFeature{
|
||||
Type: "Feature",
|
||||
DeviceInfoResponse: &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
|
||||
|
||||
}
|
||||
|
||||
func SaveDeviceInfoToDB(deviceInfo models.DeviceInfo, rawData []byte) (models.DeviceInfo, models.Device, error) {
|
||||
deviceInfo.RawJSON = string(rawData)
|
||||
deviceInfo.X = deviceInfo.AccInfo.X
|
||||
deviceInfo.Y = deviceInfo.AccInfo.Y
|
||||
deviceInfo.Z = deviceInfo.AccInfo.Z
|
||||
|
||||
var device models.Device
|
||||
if err := shared.GetDb().Unscoped().Where("device_id = ?", deviceInfo.ExternalDeviceID).First(&device).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
newDevice := models.Device{
|
||||
IMEI: deviceInfo.IMEI,
|
||||
IMSI: deviceInfo.IMSI,
|
||||
DeviceID: deviceInfo.ExternalDeviceID,
|
||||
DeviceConfiguration: string(rawData),
|
||||
}
|
||||
if err := shared.GetDb().Create(&newDevice).Error; err != nil {
|
||||
return deviceInfo, device, fmt.Errorf("CREATE -Device DB Error: %v", err)
|
||||
}
|
||||
deviceInfo.DeviceID = newDevice.ID
|
||||
} else {
|
||||
return deviceInfo, device, fmt.Errorf("CREATE -Device DB Error: %v", err)
|
||||
}
|
||||
} else {
|
||||
if device.DeletedAt.Valid {
|
||||
if err := shared.GetDb().Exec("UPDATE devices SET deleted_at = NULL, company_id = NULL WHERE id = ?", device.ID).Error; err != nil {
|
||||
return deviceInfo, device, fmt.Errorf("UNDELETE -Device DB Error: %v", err)
|
||||
}
|
||||
}
|
||||
deviceInfo.DeviceID = device.ID
|
||||
}
|
||||
|
||||
if err := shared.GetDb().Create(&deviceInfo).Error; err != nil {
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
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 <- notification
|
||||
messagingChannel <- sellerNotification
|
||||
}
|
||||
}(deviceInfo)
|
||||
|
||||
return deviceInfo, device, nil
|
||||
}
|
||||
|
||||
func CountDeviceInfoByCompany(companyID uint) (int64, error) {
|
||||
var contracts []models.Contract
|
||||
var allDeviceIDs []int64
|
||||
var count int64
|
||||
|
||||
// Find all contracts where the company is either a buyer or a seller
|
||||
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, err
|
||||
}
|
||||
|
||||
// Aggregate all DeviceIDs from these contracts
|
||||
for _, contract := range contracts {
|
||||
allDeviceIDs = append(allDeviceIDs, contract.DeviceIDs...)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// 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...)
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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 total counts
|
||||
inRangeCount += inRange
|
||||
outOfRangeCount += outOfRange
|
||||
}
|
||||
}
|
||||
|
||||
return inRangeCount, outOfRangeCount, monthlyCounts, nil
|
||||
}
|
||||
|
||||
type ContractLocationMatch struct {
|
||||
ContractID uint
|
||||
DeviceInfoID uint
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
//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
|
||||
|
||||
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
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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 shared.DistanceKm(contract.StartLat, contract.StartLon, deviceInfo.Lat, deviceInfo.Lon) <= 1 ||
|
||||
shared.DistanceKm(contract.EndLat, contract.EndLon, deviceInfo.Lat, deviceInfo.Lon) <= 1 {
|
||||
|
||||
results = append(results, ContractLocationMatch{
|
||||
ContractID: contract.ID,
|
||||
DeviceInfoID: deviceInfo.ID,
|
||||
})
|
||||
registeredDevices[deviceInfo.DeviceID] = true // Mark this device as registered
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
114
database/invoice/invoice.go
Normal file
114
database/invoice/invoice.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package invoice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
func GetInvoices(buyerName string, sortBy string, limit int, offset int, ids []int64, status []string, company int) ([]models.Invoice, int64, error) {
|
||||
var invoices []models.Invoice
|
||||
|
||||
// Default sort by InvoiceDate DESC
|
||||
sortField := "invoice_date"
|
||||
sortOrder := "desc"
|
||||
|
||||
if sortBy == "InvoiceDate" || sortBy == "InvoiceDueDate" {
|
||||
sortField = strings.ToLower(sortBy)
|
||||
}
|
||||
|
||||
dbOrder := fmt.Sprintf("%s %s", sortField, sortOrder)
|
||||
|
||||
db := shared.GetDb()
|
||||
countDb := db
|
||||
|
||||
if buyerName != "" {
|
||||
db = db.Where("buyer_name LIKE ?", "%"+buyerName+"%")
|
||||
countDb = countDb.Where("buyer_name LIKE ?", "%"+buyerName+"%")
|
||||
}
|
||||
|
||||
// Added conditional for ID search
|
||||
if len(ids) > 0 {
|
||||
db = db.Where("id in (?)", ids)
|
||||
countDb = countDb.Where("id in (?)", ids)
|
||||
}
|
||||
|
||||
// Added conditional for status search
|
||||
if len(status) > 0 {
|
||||
db = db.Where("status in (?)", status)
|
||||
countDb = countDb.Where("status in (?)", status)
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := countDb.Model(&models.Invoice{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := db.Preload("InvoiceItem").
|
||||
Order(dbOrder).
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Find(&invoices).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
for i := range invoices {
|
||||
var sum int64
|
||||
if invoices[i].InvoiceItem != nil {
|
||||
for _, item := range invoices[i].InvoiceItem {
|
||||
sum += item.PriceCents * item.Quantity
|
||||
}
|
||||
invoices[i].PriceCents = sum
|
||||
}
|
||||
}
|
||||
|
||||
return invoices, total, nil
|
||||
}
|
||||
|
||||
func CountInvoicesByMultipleStatuses(companyID uint, startTime, endTime time.Time) (int64, int64, map[string]map[string]int64, error) {
|
||||
var claimed, issued int64
|
||||
monthlyCounts := make(map[string]map[string]int64)
|
||||
|
||||
// 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{"insurance_claimed": 0, "invoice_issued": 0}
|
||||
|
||||
// Query for 'insurance_claimed' invoices for the current month
|
||||
var monthlyClaimed int64
|
||||
err := shared.GetDb().Model(&models.Invoice{}).
|
||||
Where("status = ? AND (buyer_id = ? OR seller_id = ?) AND invoice_date >= ? AND invoice_due_date <= ?", "insurance_claimed", companyID, companyID, dt, monthEnd).
|
||||
Count(&monthlyClaimed).Error
|
||||
if err != nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
|
||||
// Query for 'invoice_issued' invoices for the current month
|
||||
var monthlyIssued int64
|
||||
err = shared.GetDb().Model(&models.Invoice{}).
|
||||
Where("status = ? AND (buyer_id = ? OR seller_id = ?) AND invoice_date >= ? AND invoice_due_date <= ?", "invoice_issued", companyID, companyID, dt, monthEnd).
|
||||
Count(&monthlyIssued).Error
|
||||
if err != nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
|
||||
// Update the counts for the current month
|
||||
monthlyCounts[monthKey]["insurance_claimed"] = monthlyClaimed
|
||||
monthlyCounts[monthKey]["invoice_issued"] = monthlyIssued
|
||||
|
||||
// Update the total counts
|
||||
claimed += monthlyClaimed
|
||||
issued += monthlyIssued
|
||||
}
|
||||
|
||||
return claimed, issued, monthlyCounts, nil
|
||||
}
|
||||
44
database/notification/notificaiton.go
Normal file
44
database/notification/notificaiton.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
|
||||
func GetNotificationsForCompanyID(companyID int, afterTime time.Time) ([]models.GetNotificationsResponse, int, error) {
|
||||
// Create a slice to hold the notifications
|
||||
var notifications []models.Notification
|
||||
var customNotifications []models.GetNotificationsResponse
|
||||
|
||||
// Fetch notifications from the database based on UserID and creation time
|
||||
if err := shared.GetDb().Where("company_id = ? AND created_at > ?", companyID, afterTime).Find(¬ifications).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Printf("GetNotificationsForCompanyID Error: No notifications found: %v", err)
|
||||
return customNotifications, http.StatusNotFound, err
|
||||
} else {
|
||||
log.Printf("GetNotificationsForCompanyID Error: Database error: %v", err)
|
||||
return customNotifications, http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
|
||||
// Transform to custom response format
|
||||
for _, n := range notifications {
|
||||
customNotification := models.GetNotificationsResponse{
|
||||
Type: n.NotificationType,
|
||||
Title: n.Title,
|
||||
Message: n.Text,
|
||||
DateTime: n.CreatedAt,
|
||||
}
|
||||
customNotifications = append(customNotifications, customNotification)
|
||||
}
|
||||
|
||||
return customNotifications, http.StatusOK, nil
|
||||
|
||||
}
|
||||
126
database/user/user.go
Normal file
126
database/user/user.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func SaveResetTokenToDB(userID uint, resetToken string) error {
|
||||
// Calculate the expiry date (one month from now)
|
||||
expiryDate := time.Now().AddDate(0, 1, 0).Format(time.RFC3339)
|
||||
|
||||
// Create a new PasswordTokens instance
|
||||
passwordToken := models.PasswordTokens{
|
||||
UserID: userID,
|
||||
Token: resetToken,
|
||||
ExpiryDate: expiryDate,
|
||||
}
|
||||
|
||||
// Save the password token to the database
|
||||
if err := shared.GetDb().Create(&passwordToken).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetUserByEmail(email string) (*models.User, error) {
|
||||
var user models.User
|
||||
|
||||
// Query the database for a user with the specified email and preload Companies
|
||||
if err := shared.GetDb().Preload("Companies").Where("email = ?", email).First(&user).Error; err != nil {
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func CheckPassword(hashedPassword, password string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func CreateSessionToken(userID, companyID uint) (string, error) {
|
||||
// Generate JWT token
|
||||
tokenString, err := CreateJWTToken(userID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Create and save the session token in the database
|
||||
sessionToken := models.SessionToken{
|
||||
UserID: userID,
|
||||
Token: tokenString,
|
||||
CompanyID: companyID,
|
||||
IsActive: true,
|
||||
}
|
||||
if result := shared.GetDb().Create(&sessionToken); result.Error != nil {
|
||||
return "", result.Error
|
||||
}
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
func ResetLoginAttempts(user models.User) {
|
||||
user.LoginAttempts = 0
|
||||
user.IsActive = true
|
||||
shared.GetDb().Save(&user)
|
||||
}
|
||||
|
||||
func IncrementLoginAttempts(user models.User) {
|
||||
user.LoginAttempts++
|
||||
if user.LoginAttempts >= 10 {
|
||||
user.IsActive = false
|
||||
}
|
||||
shared.GetDb().Save(&user)
|
||||
}
|
||||
|
||||
func CreateJWTToken(userID uint) (string, error) {
|
||||
var jwtKey = []byte(config.AppConfig.Service.JwtSecretKey)
|
||||
expiryHours, err := strconv.Atoi(config.AppConfig.Service.JwtSecretKeyExpiryHours)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
expirationTime := time.Now().Add(time.Duration(expiryHours) * time.Hour)
|
||||
claims := &jwt.StandardClaims{
|
||||
Subject: fmt.Sprint(userID),
|
||||
ExpiresAt: expirationTime.Unix(),
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString(jwtKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
func InvalidateSessionToken(tokenString string) error {
|
||||
// Find the session token in the database
|
||||
var sessionToken models.SessionToken
|
||||
result := shared.GetDb().Where("token = ?", tokenString).First(&sessionToken)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
// If token is not found, you may choose to ignore or handle it as an error
|
||||
return nil // or return result.Error for strict handling
|
||||
}
|
||||
return result.Error
|
||||
}
|
||||
|
||||
return shared.GetDb().Delete(&sessionToken).Error
|
||||
}
|
||||
11
env-example
11
env-example
@@ -6,4 +6,13 @@ NOVATECH_DATABASE_USERNAME=username
|
||||
NOVATECH_DATABASE_PASSWORD=password
|
||||
NOVATECH_DATABASE_NAME=dbname
|
||||
NOVATECH_DATABASE_ADDRESS=localhost
|
||||
NOVATECH_DATABASE_PORT=5432
|
||||
NOVATECH_DATABASE_PORT=5432
|
||||
NOVATECH_SERVICE_BLOCKCHAIN_SECRET="abc&1*~#^2^#s0^=)^^7%b34"
|
||||
NOVATECH_BLOCKCHAIN_NETWORK_ENDPOINT="https://polygon-mumbai.infura.io/v3/4458cf4d1689497b9a38b1d6bbf05e78"
|
||||
NOVATECH_BLOCKCHAIN_CONTRACT_ADDRESS=0x121Cb4bFEeDb55d598D8F5e9EeDF8bB14c421d96
|
||||
NOVATECH_BLOCKCHAIN_WALLET_ADDRESS=0x20eff5decaed29bd64f0c6385956363eeaaf4d3e
|
||||
NOVATECH_BLOCKCHAIN_WALLET_PRIVATE_KEY=PRIVATE_KEY
|
||||
NOVATECH_SERVICE_MAPBOX_ACCESS_TOKEN=pk.ey
|
||||
AWS_ACCESS_KEY_ID:access
|
||||
AWS_SECRET_ACCESS_KEY:secret
|
||||
JWT_SECRET_KEY:key
|
||||
|
||||
99
go.mod
99
go.mod
@@ -1,45 +1,93 @@
|
||||
module novatech
|
||||
module gitlab.com/pactual1/backend
|
||||
|
||||
go 1.21.0
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/VoidArtanis/go-rest-boilerplate v0.0.0-20171106114442-315cdd5f775f
|
||||
github.com/aws/aws-sdk-go v1.46.6
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/ethereum/go-ethereum v1.13.1
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/mattn/go-sqlite3 v1.14.0
|
||||
github.com/lib/pq v1.8.0
|
||||
github.com/mailru/easyjson v0.7.7
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/qor/admin v1.2.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/valyala/fasthttp v1.40.0
|
||||
golang.org/x/crypto v0.14.0
|
||||
)
|
||||
|
||||
replace gitlab.com/pactual1/backend => ./
|
||||
|
||||
require (
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/chris-ramon/douceur v0.2.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
|
||||
github.com/bytedance/sonic v1.10.1 // indirect
|
||||
github.com/cespare/cp v1.1.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.0 // indirect
|
||||
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||
github.com/cockroachdb/pebble v0.0.0-20230917032534-be1586403c9b // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/consensys/bavard v0.1.13 // indirect
|
||||
github.com/consensys/gnark-crypto v0.11.3-0.20230906172141-49815a21349a // indirect
|
||||
github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deckarep/golang-set/v2 v2.3.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/ethereum/c-kzg-4844 v0.3.1 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/fjl/memsize v0.0.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
|
||||
github.com/getsentry/sentry-go v0.24.1 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.15.4 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/gorilla/context v1.1.1 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/gorilla/sessions v1.2.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/gosimple/slug v1.9.0 // indirect
|
||||
github.com/hashicorp/go-bexpr v0.1.13 // indirect
|
||||
github.com/holiman/uint256 v1.2.3 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/lib/pq v1.8.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.3 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.25 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
github.com/qor/assetfs v0.0.0-20170713023933-ff57fdc13a14 // indirect
|
||||
github.com/qor/middlewares v0.0.0-20170822143614-781378b69454 // indirect
|
||||
github.com/qor/qor v0.0.0-20210618082622-a52aba0a0ce1 // indirect
|
||||
@@ -48,14 +96,29 @@ require (
|
||||
github.com/qor/session v0.0.0-20170907035918-8206b0adab70 // indirect
|
||||
github.com/qor/validations v0.0.0-20171228122639-f364bca61b46 // indirect
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/rs/cors v1.10.0 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/status-im/keycard-go v0.3.0 // indirect
|
||||
github.com/supranational/blst v0.3.11 // indirect
|
||||
github.com/theplant/cldr v0.0.0-20190423050709-9f76f7ce4ee8 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.9.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
golang.org/x/arch v0.5.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
||||
|
||||
299
go.sum
299
go.sum
@@ -1,25 +1,74 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
||||
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/VoidArtanis/go-rest-boilerplate v0.0.0-20171106114442-315cdd5f775f h1:hkHclwFglpwGnXIbBEpOZ1knFtnNSSatQMesPQUS0jA=
|
||||
github.com/VoidArtanis/go-rest-boilerplate v0.0.0-20171106114442-315cdd5f775f/go.mod h1:UU6tTLCTPtCk0y7/XV7bVIZS4Ft5iYW9uaftCu3CuC4=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/aws/aws-sdk-go v1.34.20/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.46.6 h1:6wFnNC9hETIZLMf6SOTN7IcclrOGwp/n9SLp8Pjt6E8=
|
||||
github.com/aws/aws-sdk-go v1.46.6/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc=
|
||||
github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
|
||||
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
|
||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
|
||||
github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
|
||||
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||
github.com/cockroachdb/pebble v0.0.0-20230917032534-be1586403c9b h1:7xayquCpBglP/EAWRN1VElxZM45cT7lR/w7nC9Zv01A=
|
||||
github.com/cockroachdb/pebble v0.0.0-20230917032534-be1586403c9b/go.mod h1:nindLFinxeDPjP4qI9LtVHAwDef57/0s5KMfWgdktQc=
|
||||
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
|
||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
|
||||
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||
github.com/consensys/gnark-crypto v0.11.3-0.20230906172141-49815a21349a h1:Rc86uLASrW3xpeWRH8V9W23v5QYegI/wjgbZzwPiC44=
|
||||
github.com/consensys/gnark-crypto v0.11.3-0.20230906172141-49815a21349a/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A=
|
||||
github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A=
|
||||
github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
@@ -28,32 +77,69 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg=
|
||||
github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
|
||||
github.com/ethereum/go-ethereum v1.13.1 h1:UF2FaUKPIy5jeZk3X06ait3y2Q4wI+vJ1l7+UARp+60=
|
||||
github.com/ethereum/go-ethereum v1.13.1/go.mod h1:xHQKzwkHSl0gnSjZK1mWa06XEdm9685AHqhRknOzqGQ=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
|
||||
github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
|
||||
github.com/getsentry/sentry-go v0.24.1 h1:W6/0GyTy8J6ge6lVCc94WB6Gx2ZuLrgopnn9w8Hiwuk=
|
||||
github.com/getsentry/sentry-go v0.24.1/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs=
|
||||
github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
@@ -62,8 +148,22 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
|
||||
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
|
||||
github.com/hashicorp/go-bexpr v0.1.13 h1:HNwp7vZrMpRq8VZXj8VF90LbZpRjQQpim1oJF0DgSwg=
|
||||
github.com/hashicorp/go-bexpr v0.1.13/go.mod h1:gN7hRKB3s7yT+YvTdnhZVLTENejvhlkZ8UE4YVBS+Q8=
|
||||
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw=
|
||||
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
|
||||
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jinzhu/configor v1.2.0/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
|
||||
github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
@@ -75,43 +175,85 @@ github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/microcosm-cc/bluemonday v1.0.3 h1:EjVH7OqbU219kdm8acbveoclh2zZFqPJTJw6VUlTLAQ=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.3/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
|
||||
github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
||||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/qor/admin v0.0.0-20200701030804-02d81a10a8bf/go.mod h1:Sm5kX+Hkq1LKiFyqZJLnncUg8dWM/2roOEiy98NOUzA=
|
||||
github.com/qor/admin v0.0.0-20200728131616-564dfca36b14/go.mod h1:TiMo/I9p4pjVFtLI8+ellx2YbeiirVYcoh5UrQc9v9I=
|
||||
github.com/qor/admin v0.0.0-20210618081816-6df954b69f20/go.mod h1:VhWvTKxb2tdmu1GkVc6U5Oak0r7NyskTSj3ZPDQOrTI=
|
||||
@@ -155,6 +297,19 @@ github.com/qor/worker v0.0.0-20190805090529-35a245417f70 h1:EUo1U/EGuZ/CQeLvdQoq
|
||||
github.com/qor/worker v0.0.0-20190805090529-35a245417f70/go.mod h1:M+3u2k0/OiZCc4thYtdE2Cps+n5tOOfI7X7LdHUo9/k=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rs/cors v1.10.0 h1:62NOS1h+r8p1mW6FM0FSB0exioXLhd/sh15KpjWBZ+8=
|
||||
github.com/rs/cors v1.10.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/status-im/keycard-go v0.3.0 h1:i+JcpGVCR75W8ZGtWQfQgnrepBJQ2+V36BDqh1nF8bo=
|
||||
github.com/status-im/keycard-go v0.3.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
@@ -165,59 +320,135 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
|
||||
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||
github.com/theplant/cldr v0.0.0-20190423050709-9f76f7ce4ee8 h1:di0cR5qqo2DllBMwmP75kZpUX6dAXhsn1O2dshQfMaA=
|
||||
github.com/theplant/cldr v0.0.0-20190423050709-9f76f7ce4ee8/go.mod h1:MIL7SmF8wRAYDn+JexczVRUiJXTCi4VbQavsCKWKwXI=
|
||||
github.com/theplant/htmltestingutils v0.0.0-20190423050759-0e06de7b6967 h1:yPrgtU8bj7Q/XbXgjjmngZtOhsUufBAraruNwxv/eXM=
|
||||
github.com/theplant/htmltestingutils v0.0.0-20190423050759-0e06de7b6967/go.mod h1:86iN4EAYaQbx1VTW5uPslTIviRkYH8CzslMC//g+BgY=
|
||||
github.com/theplant/testingutils v0.0.0-20190603093022-26d8b4d95c61 h1:757/ruZNgTsOf5EkQBo0i3Bx/P2wgF5ljVkODeUX/uA=
|
||||
github.com/theplant/testingutils v0.0.0-20190603093022-26d8b4d95c61/go.mod h1:p22Q3Bg5ML+hdI3QSQkB/pZ2+CjfOnGugoQIoyE2Ub8=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/twinj/uuid v1.0.0 h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk=
|
||||
github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc=
|
||||
github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yosssi/gohtml v0.0.0-20200519115854-476f5b4b8047 h1:YWaOkupKL+BRRJSWRq/uhSkWXc1K0QVIYVG36XUBGOc=
|
||||
github.com/yosssi/gohtml v0.0.0-20200519115854-476f5b4b8047/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y=
|
||||
golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
|
||||
|
||||
86
main.go
86
main.go
@@ -4,12 +4,16 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"novatech/config"
|
||||
"novatech/models"
|
||||
"novatech/routes"
|
||||
"novatech/shared"
|
||||
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/routes"
|
||||
"gitlab.com/pactual1/backend/services/erp"
|
||||
"gitlab.com/pactual1/backend/services/messaging"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/qor/admin"
|
||||
)
|
||||
@@ -18,7 +22,6 @@ var DB *gorm.DB
|
||||
|
||||
func main() {
|
||||
|
||||
|
||||
// LOAD APPLICATION CONFIGURATION
|
||||
err := config.Load()
|
||||
if err != nil {
|
||||
@@ -35,31 +38,86 @@ func main() {
|
||||
Admin := admin.New(&admin.AdminConfig{DB: shared.GetDb()})
|
||||
Admin.RegisterViewPath("app/views/qor")
|
||||
fmt.Printf("Admin instance: %+v\n", Admin)
|
||||
|
||||
// Allow Admin to manage User resource
|
||||
company := Admin.AddResource(&models.Company{})
|
||||
|
||||
userResource := Admin.AddResource(&models.User{})
|
||||
|
||||
// Hide the Password field in the QOR admin UI
|
||||
userResource.EditAttrs("-Password")
|
||||
userResource.NewAttrs("-Password")
|
||||
userResource.ShowAttrs("-Password")
|
||||
// Add User and Device resources
|
||||
// Admin.AddResource(&models.User{})
|
||||
Admin.AddResource(&models.Device{})
|
||||
Admin.AddResource(&models.ProductTemplate{})
|
||||
company.Meta(&admin.Meta{Name: "Users", Config: &admin.SelectManyConfig{SelectMode: "bottom_sheet"}})
|
||||
company.Meta(&admin.Meta{Name: "Devices", Config: &admin.SelectManyConfig{SelectMode: "bottom_sheet"}})
|
||||
|
||||
// Add User and Device resources
|
||||
Admin.AddResource(&models.User{})
|
||||
Admin.AddResource(&models.Device{})
|
||||
// Initialize HTTP request multiplexer
|
||||
// // Initialize HTTP request multiplexe
|
||||
mux := http.NewServeMux()
|
||||
// Mount admin interface to mux
|
||||
// // Mount admin interface to mux
|
||||
Admin.MountTo("/admin", mux)
|
||||
|
||||
// // Setup Admin
|
||||
// Admin := admin.New(&admin.AdminConfig{DB: shared.GetDb()})
|
||||
// Admin.AddResource(&models.Student{})
|
||||
// school := Admin.AddResource(&models.School{})
|
||||
// school.Meta(&admin.Meta{Name: "Students", Config: &admin.SelectManyConfig{SelectMode: "select"}})
|
||||
// Admin.MountTo("/admin", mux)
|
||||
|
||||
// school.SaveHandler = func(value interface{}, ctx *qor.Context) error {
|
||||
// schoolRecord := value.(*models.School)
|
||||
// log.Printf("Executed handler %v", schoolRecord)
|
||||
// log.Printf("Executed handler %v", schoolRecord.Students)
|
||||
|
||||
// return ctx.GetDB().Save(schoolRecord).Error
|
||||
// }
|
||||
|
||||
// Start the admin server in a separate goroutine
|
||||
go func() {
|
||||
port := config.AppConfig.Service.Port
|
||||
port := config.AppConfig.Service.Port
|
||||
fmt.Println("Admin server listening on :" + port)
|
||||
http.ListenAndServe(":" + port, mux)
|
||||
http.ListenAndServe(":"+port, mux)
|
||||
}()
|
||||
|
||||
// Temp fix to add UUID to existing contracts
|
||||
var contracts []models.Contract
|
||||
result := shared.GetDb().Where("uuid IS NULL").Find(&contracts)
|
||||
if result.Error != nil {
|
||||
log.Printf("Error fetching contracts: %v", result.Error)
|
||||
return
|
||||
}
|
||||
|
||||
for _, contract := range contracts {
|
||||
contract.UUID = uuid.New().String()
|
||||
shared.GetDb().Save(&contract)
|
||||
}
|
||||
|
||||
// Initialize channels
|
||||
// messagingChannel := make(chan string)
|
||||
erpChannel := make(chan string)
|
||||
|
||||
// Start services and pass the respective channels
|
||||
notificationCh := make(chan models.Notification, 100)
|
||||
// Start services and pass the respective channels
|
||||
emailCh := make(chan models.EmailNotification, 100)
|
||||
// Create a new messaging service
|
||||
messagingService := messaging.NewService(notificationCh, emailCh, shared.GetDb())
|
||||
// Run the messaging service
|
||||
go messagingService.MessagingService()
|
||||
go messagingService.SendEmailService()
|
||||
go erp.ERPService(erpChannel)
|
||||
|
||||
// Sending messages via channels
|
||||
// messagingChannel <- "Send an email"
|
||||
erpChannel <- "Update ERP record"
|
||||
|
||||
// Initialize Gin
|
||||
r := gin.Default()
|
||||
routes.InitRouter(r)
|
||||
// Start the Gin server on another port
|
||||
port := config.AppConfig.AdminService.Port
|
||||
port := config.AppConfig.AdminService.Port
|
||||
fmt.Println("Application server listening on :" + port)
|
||||
r.Run(":" + port)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ func CORSMiddleware() gin.HandlerFunc {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, PATCH")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
@@ -20,4 +20,4 @@ func CORSMiddleware() gin.HandlerFunc {
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,18 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -83,7 +91,7 @@ func GenerateToken(key []byte, userId string, username string, roles []string) (
|
||||
claims := make(jwt.MapClaims)
|
||||
claims["user_id"] = userId
|
||||
claims["username"] = username
|
||||
claims["exp"]=time.Now().Add(time.Hour * 72).UnixNano() / int64(time.Millisecond)
|
||||
claims["exp"] = time.Now().Add(time.Hour*72).UnixNano() / int64(time.Millisecond)
|
||||
|
||||
//Set user roles
|
||||
claims["roles"] = roles
|
||||
@@ -103,3 +111,105 @@ func ValidateToken(tokenString string, key string) (*jwt.Token, error) {
|
||||
return token, err
|
||||
}
|
||||
|
||||
// AuthMiddleware checks the session token and validates it
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
// Check if contractCheckPassed is set in the context
|
||||
if passed, exists := c.Get("contractCheckPassed"); exists && passed.(bool) {
|
||||
log.Printf("checjedpass auth %v", true)
|
||||
// Skip further checks and proceed to the next middleware
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
log.Printf("checjedpass auth%v", false)
|
||||
var jwtKey = []byte(config.AppConfig.Service.JwtSecretKey)
|
||||
tokenString := c.GetHeader("Authorization")
|
||||
|
||||
// Check if token is in the correct format (Bearer token)
|
||||
if len(tokenString) > 7 && strings.ToUpper(tokenString[0:7]) == "BEARER " {
|
||||
tokenString = tokenString[7:]
|
||||
} else {
|
||||
c.JSON(http.StatusForbidden, gin.H{"message": "Your request is not authorized"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Parse and validate the token
|
||||
claims := &jwt.StandardClaims{}
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return jwtKey, nil
|
||||
})
|
||||
|
||||
if err != nil || !token.Valid {
|
||||
c.JSON(http.StatusForbidden, gin.H{"message": "Invalid authorization token"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the token is present and active in the SessionToken table
|
||||
var sessionToken models.SessionToken
|
||||
result := shared.GetDb().Where("token = ? AND is_active = ?", tokenString, true).First(&sessionToken)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"message": "Invalid session token"})
|
||||
c.Abort()
|
||||
return
|
||||
} else if result.Error != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "Internal server error"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Set user ID in the Gin context
|
||||
c.Set("userID", sessionToken.UserID)
|
||||
c.Set("companyID", sessionToken.CompanyID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func ContractCheckMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
db := shared.GetDb()
|
||||
var contractID uint
|
||||
var uuid string
|
||||
|
||||
// Handling for POST requests
|
||||
if c.Request.Method == "POST" {
|
||||
var payload struct {
|
||||
UUID string `json:"uuid"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&payload); err == nil {
|
||||
uuid = payload.UUID
|
||||
}
|
||||
}
|
||||
|
||||
// Handling for GET requests
|
||||
if c.Request.Method == "GET" {
|
||||
uuid = c.Query("uuid")
|
||||
}
|
||||
|
||||
log.Printf("uuid %v", uuid)
|
||||
log.Printf("contractID %v", contractID)
|
||||
|
||||
// Perform the check only if both contractID and uuid are provided
|
||||
if uuid != "" {
|
||||
var contract models.Contract
|
||||
result := db.Where("uuid = ?", uuid).First(&contract)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"message": "Invalid contract ID or UUID"})
|
||||
c.Abort()
|
||||
return
|
||||
} else if result.Error != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "Internal server error"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Set a flag in the context to indicate a successful contract check
|
||||
c.Set("contractCheckPassed", true)
|
||||
log.Printf("checjedpass %v", true)
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,53 @@
|
||||
package models
|
||||
|
||||
import "github.com/jinzhu/gorm"
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BaseModel struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
DeletedAt sql.NullTime `json:"deletedAt,omitempty" gorm:"index"`
|
||||
}
|
||||
|
||||
type Company struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
Password string
|
||||
Email string
|
||||
Avatar string
|
||||
Users []User
|
||||
Devices []Device
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
Users []User `gorm:"many2many:user_companies;"`
|
||||
Devices []Device `json:"devices"`
|
||||
IsBuyer bool `json:"isBuyer"`
|
||||
}
|
||||
|
||||
type School struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
Students []Student `json:"students" gorm:"foreignKey:SchoolID"`
|
||||
}
|
||||
|
||||
// func FetchCompanies(companies *[]Company) (err error) {
|
||||
// db := gorm.GetDb()
|
||||
type Student struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
SchoolID uint `json:"schoolId" gorm:"index"`
|
||||
}
|
||||
|
||||
// if err = db.Find(companies).Error; err != nil {
|
||||
// return err
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
type CompanyShortResponse struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (Company)Update() (bool, error) {
|
||||
func (Company) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Company)Create() (bool, error) {
|
||||
func (Company) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Company)Delete() (bool, error) {
|
||||
func (Company) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
362
models/contract.go
Normal file
362
models/contract.go
Normal file
@@ -0,0 +1,362 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
type Contract struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
UUID string `json:"uuid" gorm:"type:uuid;"`
|
||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||
BuyerID uint `json:"buyerId"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
Description string `json:"description"`
|
||||
StartPlaceName string `json:"startPlaceName"`
|
||||
StartLat float64 `json:"startLat"`
|
||||
StartLon float64 `json:"startLon"`
|
||||
EndPlaceName string `json:"endPlaceName"`
|
||||
EndLat float64 `json:"endLat"`
|
||||
EndLon float64 `json:"endLon"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Status string `json:"status"`
|
||||
BlockchainSecret string `json:"blockchainSecret"`
|
||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||
ProductID uint `json:"productId"`
|
||||
TemplateID uint `json:"templateId"`
|
||||
MaxTemp float64 `json:"maxTemp"`
|
||||
MinTemp float64 `json:"minTemp"`
|
||||
ArrivalDate time.Time `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
BuyerName string `json:"buyerName" gorm:"-"`
|
||||
SellerName string `json:"sellerName" gorm:"-"`
|
||||
ProductName string `json:"productName" gorm:"-"`
|
||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||
DevicesImeis []string `json:"devicesImeis" gorm:"-"`
|
||||
DevicesImeisScanner PQStringArray `json:"contractDevicesImeis" gorm:"-"`
|
||||
}
|
||||
|
||||
type PQStringArray []string
|
||||
|
||||
func (a *PQStringArray) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// The database driver will give us a string in the format "{item1,item2,item3}"
|
||||
// We need to convert this to a slice
|
||||
var str string
|
||||
switch src := src.(type) {
|
||||
case []byte:
|
||||
str = string(src)
|
||||
case string:
|
||||
str = src
|
||||
default:
|
||||
return errors.New("incompatible type for PQStringArray")
|
||||
}
|
||||
|
||||
// Remove the curly braces and split the string
|
||||
str = strings.Trim(str, "{}")
|
||||
if str != "" {
|
||||
*a = strings.Split(str, ",")
|
||||
} else {
|
||||
*a = []string{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DashboardContractResponse struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||
BuyerID uint `json:"buyerId"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
Description string `json:"description"`
|
||||
StartLat float64 `json:"startLat"`
|
||||
StartLon float64 `json:"startLon"`
|
||||
EndLat float64 `json:"endLat"`
|
||||
EndLon float64 `json:"endLon"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Status string `json:"status"`
|
||||
BlockchainID string `json:"blockchainId"`
|
||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||
ProductID uint `json:"productId"`
|
||||
MaxTemp float64 `json:"maxTemp"`
|
||||
MinTemp float64 `json:"minTemp"`
|
||||
ArrivalDate time.Time `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
BuyerName string `json:"buyerName" gorm:"-"`
|
||||
NumberOfDevices int `json:"numberOfDevices" gorm:"-"`
|
||||
}
|
||||
|
||||
type ContractResponse struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
DeviceIDs pq.Int64Array `json:"deviceIds" gorm:"type:integer[]"`
|
||||
Seller struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"seller"`
|
||||
Buyer struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"buyer"`
|
||||
Start struct {
|
||||
Name string `json:"name"`
|
||||
Lat float64 `json:"lat"`
|
||||
Lon float64 `json:"lon"`
|
||||
Time time.Time `json:"time"`
|
||||
} `json:"start"`
|
||||
End struct {
|
||||
Name string `json:"name"`
|
||||
Lat float64 `json:"lat"`
|
||||
Lon float64 `json:"lon"`
|
||||
Time time.Time `json:"time"`
|
||||
} `json:"end"`
|
||||
Product struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"product"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
BlockchainID string `json:"blockchainId"`
|
||||
ContractInfos []ContractInfo `json:"contractInfos"`
|
||||
MaxTemp float64 `json:"maxTemp"`
|
||||
MinTemp float64 `json:"minTemp"`
|
||||
ArrivalDate time.Time `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
DeviceImeis []string `json:"devicesImeis"`
|
||||
}
|
||||
|
||||
func ConvertContractsToContractResponse(contracts []Contract) []ContractResponse {
|
||||
contractResponses := []ContractResponse{}
|
||||
for _, contract := range contracts {
|
||||
contractResponse := ConvertContractToContractResponse(contract)
|
||||
contractResponses = append(contractResponses, contractResponse)
|
||||
}
|
||||
return contractResponses
|
||||
}
|
||||
|
||||
func ConvertContractToContractResponse(contract Contract) ContractResponse {
|
||||
contractResponse := ContractResponse{
|
||||
BaseModel: BaseModel{ID: contract.ID, CreatedAt: contract.CreatedAt, UpdatedAt: contract.UpdatedAt},
|
||||
Name: contract.Name,
|
||||
DeviceIDs: contract.DeviceIDs,
|
||||
Seller: struct {
|
||||
ID uint "json:\"id\""
|
||||
Name string "json:\"name\""
|
||||
}{
|
||||
ID: contract.SellerID,
|
||||
Name: contract.SellerName,
|
||||
},
|
||||
Buyer: struct {
|
||||
ID uint "json:\"id\""
|
||||
Name string "json:\"name\""
|
||||
}{
|
||||
ID: contract.BuyerID,
|
||||
Name: contract.BuyerName,
|
||||
},
|
||||
Start: struct {
|
||||
Name string "json:\"name\""
|
||||
Lat float64 "json:\"lat\""
|
||||
Lon float64 "json:\"lon\""
|
||||
Time time.Time "json:\"time\""
|
||||
}{
|
||||
Name: contract.StartPlaceName,
|
||||
Lat: contract.StartLat,
|
||||
Lon: contract.StartLon,
|
||||
Time: contract.StartTime,
|
||||
},
|
||||
End: struct {
|
||||
Name string "json:\"name\""
|
||||
Lat float64 "json:\"lat\""
|
||||
Lon float64 "json:\"lon\""
|
||||
Time time.Time "json:\"time\""
|
||||
}{
|
||||
Name: contract.EndPlaceName,
|
||||
Lat: contract.EndLat,
|
||||
Lon: contract.EndLon,
|
||||
Time: contract.EndTime,
|
||||
},
|
||||
Product: struct {
|
||||
ID uint "json:\"id\""
|
||||
Name string "json:\"name\""
|
||||
}{
|
||||
ID: contract.ProductID,
|
||||
Name: contract.ProductName,
|
||||
},
|
||||
Description: contract.Description,
|
||||
Status: contract.Status,
|
||||
BlockchainID: contract.BlockchainSecret,
|
||||
ContractInfos: contract.ContractInfos,
|
||||
MaxTemp: contract.MaxTemp,
|
||||
MinTemp: contract.MinTemp,
|
||||
ArrivalDate: contract.ArrivalDate,
|
||||
PenaltyType: contract.PenaltyType,
|
||||
PenaltyValue: contract.PenaltyValue,
|
||||
PenaltyRec: contract.PenaltyRec,
|
||||
DeviceImeis: contract.DevicesImeis,
|
||||
}
|
||||
|
||||
return contractResponse
|
||||
}
|
||||
|
||||
func ConvertContractToDashboardResponse(contracts []Contract) []DashboardContractResponse {
|
||||
contractResponses := []DashboardContractResponse{}
|
||||
for _, contract := range contracts {
|
||||
contractResponse := DashboardContractResponse{
|
||||
BaseModel: BaseModel{
|
||||
ID: contract.ID,
|
||||
CreatedAt: contract.CreatedAt,
|
||||
UpdatedAt: contract.UpdatedAt,
|
||||
},
|
||||
Name: contract.Name,
|
||||
DeviceIDs: contract.DeviceIDs,
|
||||
BuyerID: contract.BuyerID,
|
||||
SellerID: contract.SellerID,
|
||||
Description: contract.Description,
|
||||
StartLat: contract.StartLat,
|
||||
StartLon: contract.StartLon,
|
||||
EndLat: contract.EndLat,
|
||||
EndLon: contract.EndLon,
|
||||
StartTime: contract.StartTime,
|
||||
EndTime: contract.EndTime,
|
||||
Status: contract.Status,
|
||||
BlockchainID: contract.BlockchainSecret,
|
||||
ContractInfos: contract.ContractInfos,
|
||||
ProductID: contract.ProductID,
|
||||
MaxTemp: contract.MaxTemp,
|
||||
MinTemp: contract.MinTemp,
|
||||
ArrivalDate: contract.ArrivalDate,
|
||||
PenaltyType: contract.PenaltyType,
|
||||
PenaltyValue: contract.PenaltyValue,
|
||||
PenaltyRec: contract.PenaltyRec,
|
||||
BuyerName: contract.BuyerName,
|
||||
NumberOfDevices: contract.NumberOfDevices,
|
||||
}
|
||||
contractResponses = append(contractResponses, contractResponse)
|
||||
}
|
||||
return contractResponses
|
||||
}
|
||||
|
||||
func ConvertContractToListResponse(contracts []Contract) []ListContractResponse {
|
||||
listInvoiceResponses := []ListContractResponse{}
|
||||
|
||||
// Get all statuses
|
||||
statuses := GetContractStatuses()
|
||||
statusMap := make(map[string]Status)
|
||||
for _, s := range statuses {
|
||||
statusMap[s.Key] = s
|
||||
}
|
||||
|
||||
for _, contract := range contracts {
|
||||
// Get the status based on Value in the DB
|
||||
status, ok := statusMap[contract.Status]
|
||||
if !ok {
|
||||
status = Status{Key: "", Value: ""}
|
||||
}
|
||||
|
||||
listInvoiceResponse := ListContractResponse{
|
||||
Status: KeyValue{Key: status.Key, Value: status.Value},
|
||||
Buyer: CompanyShortResponse{ID: int(contract.BuyerID), Name: contract.BuyerName},
|
||||
ContractID: int(contract.ID),
|
||||
ContractName: contract.Name,
|
||||
DateCreated: contract.CreatedAt,
|
||||
NumberOfDevices: contract.NumberOfDevices,
|
||||
DeviceImeis: contract.DevicesImeis,
|
||||
}
|
||||
listInvoiceResponses = append(listInvoiceResponses, listInvoiceResponse)
|
||||
}
|
||||
return listInvoiceResponses
|
||||
|
||||
}
|
||||
|
||||
const ContractStatusActive = "active"
|
||||
const ContractStatusPending = "pending"
|
||||
const ContractStatusDraft = "draft"
|
||||
const ContractStatusSigned = "signed"
|
||||
const ContractStatusReadyForActivation = "ready_for_activation"
|
||||
const ContractStatusExecuted = "executed"
|
||||
const ContractStatusRevoked = "revoked"
|
||||
|
||||
const PenaltyTypeAmount = "amount"
|
||||
const PenaltyTypePercentage = "percentage"
|
||||
|
||||
const PenaltyRecDaily = "daily"
|
||||
const PenaltyRecMonthly = "monthly"
|
||||
|
||||
type Status struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type ActiveContractsResponse struct {
|
||||
ActiveCount int64 `json:"active"`
|
||||
ExecutedCount int64 `json:"executed"`
|
||||
MonthlyContracts map[string]map[string]int64 `json:"monthly"`
|
||||
}
|
||||
|
||||
func GetContractStatuses() []Status {
|
||||
return []Status{
|
||||
{Value: "Active", Key: "active"},
|
||||
{Value: "Pending signature", Key: "pending"},
|
||||
{Value: "Draft", Key: "draft"},
|
||||
{Value: "Signed", Key: "signed"},
|
||||
{Value: "Ready for Activation", Key: "ready_for_activation"},
|
||||
{Value: "Executed", Key: "executed"},
|
||||
{Value: "Revoked", Key: "revoked"},
|
||||
}
|
||||
}
|
||||
|
||||
type ListContractResponse struct {
|
||||
Status KeyValue `json:"status"`
|
||||
Buyer CompanyShortResponse `json:"buyer"`
|
||||
ContractID int `json:"contractID"`
|
||||
ContractName string `json:"contractName"`
|
||||
NumberOfDevices int `json:"numberOfDevices"`
|
||||
DateCreated time.Time `json:"dateCreated"`
|
||||
DeviceImeis []string `json:"deviceImeis"`
|
||||
}
|
||||
|
||||
type CreateContractRequestPayload struct {
|
||||
SellerID uint `json:"sellerId" binding:"required"`
|
||||
BuyerID uint `json:"buyerId" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
ProductID uint `json:"productId"`
|
||||
MinTemp float64 `json:"minTemp" binding:"required"`
|
||||
MaxTemp float64 `json:"maxTemp" binding:"required"`
|
||||
ArrivalDate int64 `json:"arrivalDate"`
|
||||
PenaltyType string `json:"penaltyType"`
|
||||
PenaltyValue int `json:"penaltyValue"`
|
||||
PenaltyRec string `json:"penaltyRec"`
|
||||
StartPlaceName string `json:"startPlaceName"`
|
||||
StartLat float64 `json:"startLat"`
|
||||
StartLon float64 `json:"startLon"`
|
||||
EndPlaceName string `json:"endPlaceName"`
|
||||
EndLat float64 `json:"endLat"`
|
||||
EndLon float64 `json:"endLon"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (Contract) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Contract) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Contract) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
16
models/contract_info.go
Normal file
16
models/contract_info.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package models
|
||||
|
||||
type ContractInfo struct {
|
||||
BaseModel
|
||||
RawJSON string `json:"raw_json" gorm:"type:json"`
|
||||
}
|
||||
|
||||
func (ContractInfo) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (ContractInfo) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (ContractInfo) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
package models
|
||||
|
||||
type SimpleCRUD interface {
|
||||
Create() (bool,error)
|
||||
Update()( bool,error)
|
||||
Delete() (bool,error)
|
||||
|
||||
Create() (bool, error)
|
||||
Update() (bool, error)
|
||||
Delete() (bool, error)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,76 @@
|
||||
package models
|
||||
|
||||
import "github.com/jinzhu/gorm"
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
gorm.Model
|
||||
DeviceName string
|
||||
DeviceConfiguration string `gorm:"type:json"`
|
||||
CompanyID uint
|
||||
BaseModel
|
||||
DeviceID string `json:"deviceId"`
|
||||
DeviceName string `json:"deviceName"`
|
||||
IMEI string `json:"imei"`
|
||||
IMSI string `json:"imsi"`
|
||||
DeviceConfiguration string `json:"deviceConfiguration" gorm:"type:json"`
|
||||
CompanyID uint `json:"companyId"`
|
||||
DeviceInfos *[]DeviceInfo `json:"deviceInfos"`
|
||||
CurrentContractID *uint `json:"currentContractId"`
|
||||
}
|
||||
|
||||
func (Device)Update() (bool, error) {
|
||||
type DeviceResponse struct {
|
||||
BaseModel
|
||||
DeviceID string `json:"deviceId"`
|
||||
DeviceName string `json:"deviceName"`
|
||||
IMEI string `json:"imei"`
|
||||
IMSI string `json:"imsi"`
|
||||
DeviceConfiguration string `json:"deviceConfiguration" gorm:"type:json"`
|
||||
CompanyID uint `json:"companyId"`
|
||||
DeviceInfos *[]DeviceInfo `json:"deviceInfos"`
|
||||
}
|
||||
|
||||
type ContractDeviceInfo struct {
|
||||
ID uint `json:"id"`
|
||||
IMEI string `json:"imei"`
|
||||
}
|
||||
|
||||
func ConvertDeviceToResponse(devices []Device) []DeviceResponse {
|
||||
var deviceResponses []DeviceResponse
|
||||
for _, device := range devices {
|
||||
if device.DeviceInfos == nil {
|
||||
emptySlice := make([]DeviceInfo, 0)
|
||||
device.DeviceInfos = &emptySlice
|
||||
}
|
||||
|
||||
deviceResponse := DeviceResponse{
|
||||
BaseModel: BaseModel{
|
||||
ID: device.ID,
|
||||
CreatedAt: device.CreatedAt,
|
||||
UpdatedAt: device.UpdatedAt,
|
||||
},
|
||||
DeviceID: device.DeviceID,
|
||||
DeviceName: device.DeviceName,
|
||||
IMEI: device.IMEI,
|
||||
IMSI: device.IMSI,
|
||||
DeviceConfiguration: device.DeviceConfiguration,
|
||||
CompanyID: device.CompanyID,
|
||||
DeviceInfos: device.DeviceInfos,
|
||||
}
|
||||
deviceResponses = append(deviceResponses, deviceResponse)
|
||||
}
|
||||
return deviceResponses
|
||||
}
|
||||
|
||||
func (Device) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Device)Create() (bool, error) {
|
||||
func (Device) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Device)Delete() (bool, error) {
|
||||
return false, nil
|
||||
func (d *Device) Delete(db *gorm.DB) (bool, error) {
|
||||
|
||||
// Soft delete the device record.
|
||||
if err := db.Delete(d).Error; err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
94
models/device_info.go
Normal file
94
models/device_info.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package models
|
||||
|
||||
// Location holds latitude and longitude.
|
||||
type Location struct {
|
||||
Lat float64 `json:"lat"`
|
||||
Lon float64 `json:"lon"`
|
||||
}
|
||||
|
||||
// ImportantInfo holds fields that are important for quick access.
|
||||
type SensorData struct {
|
||||
IMEI string `json:"imei"`
|
||||
IMSI string `json:"imsi"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Lat float64 `json:"lat"`
|
||||
Lon float64 `json:"lon"`
|
||||
WifiLoc Location `json:"wifiLocation"`
|
||||
CellLoc Location `json:"cellLocation"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
AccInfo AccelerometerInfo `json:"accelerometerInfo"`
|
||||
AccelerometerInfo
|
||||
}
|
||||
|
||||
type DeviceInfo struct {
|
||||
BaseModel
|
||||
RawJSON string `json:"raw_json" gorm:"type:json"`
|
||||
SensorData
|
||||
DeviceID uint
|
||||
ExternalDeviceID string `json:"deviceId"`
|
||||
}
|
||||
|
||||
type DeviceInfoResponse struct {
|
||||
BaseModel
|
||||
RawJSON string `json:"rawJson" gorm:"type:json"`
|
||||
SensorData
|
||||
DeviceID uint `json:"deviceId"`
|
||||
ExternalDeviceID string `json:"externalDeviceId"`
|
||||
}
|
||||
|
||||
type NormalAndBreachedDevicesResponse struct {
|
||||
Breached int64 `json:"breached"`
|
||||
Normal int64 `json:"normal"`
|
||||
MonthlyCounts map[string]map[string]int64 `json:"monthly_counts"`
|
||||
}
|
||||
|
||||
func ConvertDeviceInfoToResponse(deviceInfos []DeviceInfo) []DeviceInfoResponse {
|
||||
var deviceInfoResponses []DeviceInfoResponse
|
||||
for _, deviceInfo := range deviceInfos {
|
||||
deviceInfoResponse := DeviceInfoResponse{
|
||||
BaseModel: BaseModel{
|
||||
ID: deviceInfo.ID,
|
||||
CreatedAt: deviceInfo.CreatedAt,
|
||||
UpdatedAt: deviceInfo.UpdatedAt,
|
||||
},
|
||||
RawJSON: deviceInfo.RawJSON,
|
||||
SensorData: deviceInfo.SensorData,
|
||||
DeviceID: deviceInfo.DeviceID,
|
||||
ExternalDeviceID: deviceInfo.ExternalDeviceID,
|
||||
}
|
||||
deviceInfoResponses = append(deviceInfoResponses, deviceInfoResponse)
|
||||
}
|
||||
return deviceInfoResponses
|
||||
}
|
||||
|
||||
type AccelerometerInfo struct {
|
||||
X int64 `json:"x"`
|
||||
Y int64 `json:"y"`
|
||||
Z int64 `json:"z"`
|
||||
}
|
||||
type GeoJSONFeatureCollection struct {
|
||||
Type string `json:"type"`
|
||||
Features []GeoJSONFeature `json:"features"`
|
||||
}
|
||||
|
||||
type GeoJSONFeature struct {
|
||||
Type string `json:"type"`
|
||||
Geometry GeoJSONGeometry `json:"geometry"`
|
||||
DeviceInfoResponse *DeviceInfoResponse `json:"deviceInfo,omitempty"`
|
||||
Properties map[string]interface{} `json:"properties"`
|
||||
}
|
||||
|
||||
type GeoJSONGeometry struct {
|
||||
Type string `json:"type"`
|
||||
Coordinates []float64 `json:"coordinates"`
|
||||
}
|
||||
|
||||
func (DeviceInfo) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (DeviceInfo) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (DeviceInfo) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
134
models/invoice.go
Normal file
134
models/invoice.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Invoice struct {
|
||||
BaseModel
|
||||
BuyerID uint `json:"buyerId"`
|
||||
BuyerName string `json:"buyerName"`
|
||||
BuyerAddress string `json:"buyerAddress"`
|
||||
BuyerEmail string `json:"buyerEmail"`
|
||||
BuyerPhone string `json:"buyerPhone"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
SellerName string `json:"sellerName"`
|
||||
SellerAddress string `json:"sellerAddress"`
|
||||
SellerEmail string `json:"sellerEmail"`
|
||||
SellerPhone string `json:"sellerPhone"`
|
||||
PriceCents int64 `json:"priceCents" gorm:"column:price_cents"`
|
||||
Discount int64 `json:"discount"`
|
||||
Tax int64 `json:"tax"`
|
||||
TermsAndConditions string `json:"termsAndConditions"`
|
||||
InvoiceName string `json:"invoiceName"`
|
||||
InvoiceDate time.Time `json:"invoiceDate"`
|
||||
InvoiceDueDate time.Time `json:"invoiceDueDate"`
|
||||
ContractID uint `json:"contractId"`
|
||||
InvoiceItem []InvoiceItem `json:"invoiceItem"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type InvoiceResponse struct {
|
||||
BaseModel
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
DeletedAt sql.NullTime `json:"deletedAt" gorm:"index"`
|
||||
BuyerID uint `json:"buyerId"`
|
||||
BuyerName string `json:"buyerName"`
|
||||
BuyerAddress string `json:"buyerAddress"`
|
||||
BuyerEmail string `json:"buyerEmail"`
|
||||
BuyerPhone string `json:"buyerPhone"`
|
||||
SellerID uint `json:"sellerId"`
|
||||
SellerName string `json:"sellerName"`
|
||||
SellerAddress string `json:"sellerAddress"`
|
||||
SellerEmail string `json:"sellerEmail"`
|
||||
SellerPhone string `json:"sellerPhone"`
|
||||
PriceCents int64 `json:"priceCents" gorm:"column:price_cents"`
|
||||
Discount int64 `json:"discount"`
|
||||
Tax int64 `json:"tax"`
|
||||
TermsAndConditions string `json:"termsAndConditions"`
|
||||
InvoiceName string `json:"invoiceName"`
|
||||
InvoiceDate time.Time `json:"invoiceDate"`
|
||||
InvoiceDueDate time.Time `json:"invoiceDueDate"`
|
||||
ContractID uint `json:"contractId"`
|
||||
InvoiceItem []InvoiceItem `json:"invoiceItem"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func ConvertInvoiceToResponse(invoices []Invoice) []InvoiceResponse {
|
||||
invoiceResponses := []InvoiceResponse{}
|
||||
for _, invoice := range invoices {
|
||||
if invoice.InvoiceItem == nil {
|
||||
emptySlice := make([]InvoiceItem, 0)
|
||||
invoice.InvoiceItem = emptySlice
|
||||
}
|
||||
|
||||
invoiceResponse := InvoiceResponse{
|
||||
BaseModel: BaseModel{
|
||||
ID: invoice.ID,
|
||||
CreatedAt: invoice.CreatedAt,
|
||||
UpdatedAt: invoice.UpdatedAt,
|
||||
},
|
||||
BuyerID: invoice.BuyerID,
|
||||
BuyerName: invoice.BuyerName,
|
||||
BuyerAddress: invoice.BuyerAddress,
|
||||
BuyerEmail: invoice.BuyerEmail,
|
||||
BuyerPhone: invoice.BuyerPhone,
|
||||
SellerID: invoice.SellerID,
|
||||
SellerName: invoice.SellerName,
|
||||
SellerAddress: invoice.SellerAddress,
|
||||
SellerEmail: invoice.SellerEmail,
|
||||
SellerPhone: invoice.SellerPhone,
|
||||
PriceCents: invoice.PriceCents,
|
||||
Discount: invoice.Discount,
|
||||
Tax: invoice.Tax,
|
||||
TermsAndConditions: invoice.TermsAndConditions,
|
||||
InvoiceName: invoice.InvoiceName,
|
||||
InvoiceDate: invoice.InvoiceDate,
|
||||
InvoiceDueDate: invoice.InvoiceDueDate,
|
||||
ContractID: invoice.ContractID,
|
||||
InvoiceItem: invoice.InvoiceItem,
|
||||
Status: invoice.Status,
|
||||
}
|
||||
invoiceResponses = append(invoiceResponses, invoiceResponse)
|
||||
}
|
||||
return invoiceResponses
|
||||
}
|
||||
|
||||
type ListInvoiceResponse struct {
|
||||
Status KeyValue `json:"status"`
|
||||
Buyer CompanyShortResponse `json:"buyer"`
|
||||
ContractID int `json:"contractId"`
|
||||
DateCreated time.Time `json:"dateCreated"`
|
||||
DueDate time.Time `json:"dueDate"`
|
||||
Amount string `json:"amount"`
|
||||
}
|
||||
type KeyValue struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type ActiveInvoiceResponse struct {
|
||||
Claimed int64 `json:"issued"`
|
||||
Issued int64 `json:"claimed"`
|
||||
MonthlyInvoices map[string]map[string]int64 `json:"monthly"`
|
||||
}
|
||||
|
||||
func GetInvoiceStatuses() []Status {
|
||||
return []Status{
|
||||
{Key: "Insurance claimed", Value: "insurance_claimed"},
|
||||
{Key: "Invoice issued", Value: "invoice_issued"},
|
||||
}
|
||||
}
|
||||
|
||||
func (Invoice) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Invoice) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Invoice) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
59
models/invoice_item.go
Normal file
59
models/invoice_item.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InvoiceItem struct {
|
||||
BaseModel
|
||||
Description string `json:"description"`
|
||||
Quantity int64 `json:"quantity"`
|
||||
Unit string `json:"unit"`
|
||||
PriceCents int64 `json:"priceCents" gorm:"column:price_cents"`
|
||||
InvoiceID uint `json:"invoiceId"`
|
||||
}
|
||||
|
||||
type InvoiceItemResponse struct {
|
||||
BaseModel
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
DeletedAt sql.NullTime `json:"deletedAt" gorm:"index"`
|
||||
Description string `json:"description"`
|
||||
Quantity int64 `json:"quantity"`
|
||||
Unit string `json:"unit"`
|
||||
PriceCents int64 `json:"priceCents" gorm:"column:price_cents"`
|
||||
InvoiceID uint `json:"invoiceId"`
|
||||
}
|
||||
|
||||
// ConvertSliceOfInvoiceItemToResponse converts a slice of InvoiceItem models to a slice of InvoiceItemResponse models
|
||||
func ConvertInvoiceItemToResponse(items []InvoiceItem) []InvoiceItemResponse {
|
||||
var itemResponses []InvoiceItemResponse
|
||||
for _, item := range items {
|
||||
itemResponse := InvoiceItemResponse{
|
||||
BaseModel: BaseModel{
|
||||
ID: item.ID,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
},
|
||||
Description: item.Description,
|
||||
Quantity: item.Quantity,
|
||||
Unit: item.Unit,
|
||||
PriceCents: item.PriceCents,
|
||||
InvoiceID: item.InvoiceID,
|
||||
}
|
||||
itemResponses = append(itemResponses, itemResponse)
|
||||
}
|
||||
return itemResponses
|
||||
}
|
||||
|
||||
func (InvoiceItem) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (InvoiceItem) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (InvoiceItem) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
31
models/json_type.go
Normal file
31
models/json_type.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type JSON json.RawMessage
|
||||
|
||||
// Scan scan value into Jsonb, implements sql.Scanner interface
|
||||
func (j *JSON) Scan(value interface{}) error {
|
||||
bytes, ok := value.([]byte)
|
||||
if !ok {
|
||||
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
|
||||
}
|
||||
|
||||
result := json.RawMessage{}
|
||||
err := json.Unmarshal(bytes, &result)
|
||||
*j = JSON(result)
|
||||
return err
|
||||
}
|
||||
|
||||
// Value return json value, implement driver.Valuer interface
|
||||
func (j JSON) Value() (driver.Value, error) {
|
||||
if len(j) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return json.RawMessage(j).MarshalJSON()
|
||||
}
|
||||
6
models/location.go
Normal file
6
models/location.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package models
|
||||
|
||||
type Place struct {
|
||||
Text string `json:"text"`
|
||||
Coordinates []float64 `json:"coordinates"`
|
||||
}
|
||||
38
models/notification.go
Normal file
38
models/notification.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
gorm.Model
|
||||
Title string
|
||||
NotificationType string
|
||||
Text string
|
||||
CompanyID int
|
||||
}
|
||||
|
||||
type EmailNotification struct {
|
||||
Subject string
|
||||
Email string
|
||||
Body string
|
||||
}
|
||||
|
||||
type GetNotificationsResponse struct {
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
DateTime time.Time `json:"datetime"`
|
||||
}
|
||||
|
||||
func (Notification) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Notification) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (Notification) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
18
models/password_tokens.go
Normal file
18
models/password_tokens.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package models
|
||||
|
||||
type PasswordTokens struct {
|
||||
BaseModel
|
||||
UserID uint `json:"username"`
|
||||
Token string `json:"token"`
|
||||
ExpiryDate string `json:"expiryDate"`
|
||||
}
|
||||
|
||||
func (PasswordTokens) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (PasswordTokens) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (PasswordTokens) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
18
models/product_template.go
Normal file
18
models/product_template.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package models
|
||||
|
||||
type ProductTemplate struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
ProductTemplateConfig map[string]interface{} `json:",omitempty" sql:"-"`
|
||||
Config string `json:"raw_config" gorm:"type:json"`
|
||||
}
|
||||
|
||||
func (ProductTemplate) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (ProductTemplate) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (ProductTemplate) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
19
models/session_token.go
Normal file
19
models/session_token.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
type SessionToken struct {
|
||||
BaseModel
|
||||
UserID uint `json:"userId"`
|
||||
Token string `json:"token"`
|
||||
IsActive bool `json:"isActive"`
|
||||
CompanyID uint `json:"companyID"`
|
||||
}
|
||||
|
||||
func (SessionToken) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (SessionToken) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (SessionToken) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
17
models/text_template.go
Normal file
17
models/text_template.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package models
|
||||
|
||||
type TextTemplate struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func (TextTemplate) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (TextTemplate) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (TextTemplate) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
@@ -1,22 +1,37 @@
|
||||
package models
|
||||
|
||||
import "github.com/jinzhu/gorm"
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string
|
||||
Password string
|
||||
Email string
|
||||
Avatar string
|
||||
CompanyID uint
|
||||
BaseModel
|
||||
Username string `json:"username"`
|
||||
Password string `json:"-"`
|
||||
Email string `json:"email"`
|
||||
Avatar string `json:"avatar"`
|
||||
IsActive bool `json:"isActive" gorm:"default:false"`
|
||||
// CompanyID uint `json:"companyId"`
|
||||
// Company Company
|
||||
Companies []Company `gorm:"many2many:user_companies;"`
|
||||
LoginAttempts int `gorm:"default:0"`
|
||||
}
|
||||
|
||||
func (User)Update() (bool, error) {
|
||||
type LoginRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type ResetPasswordRequest struct {
|
||||
Email string `json:"email"`
|
||||
}
|
||||
type UpdatePasswordRequest struct {
|
||||
Password string `json:"password"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (User) Update() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (User)Create() (bool, error) {
|
||||
func (User) Create() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (User)Delete() (bool, error) {
|
||||
func (User) Delete() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
794
postman/Backend.postman_collection.json
Normal file
794
postman/Backend.postman_collection.json
Normal file
@@ -0,0 +1,794 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "001ed695-e2e5-49c0-8fab-39516921370b",
|
||||
"name": "Backend",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"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": {
|
||||
"raw": "{{URL}}/contracts/create",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"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": {
|
||||
"raw": "{{URL}}/contracts/create",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"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 \"devicesImeis\": [\"352656107000002\",\"352656107000001\"],\n \"status\": \"active\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{URL}}/contracts/1",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"contracts",
|
||||
"1"
|
||||
]
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"raw": "{{URL}}/contracts/create",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"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": {
|
||||
"raw": "{{URL}}/contracts",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"contracts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Get Contracts for Buyers",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{URL}}/contracts",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"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": {
|
||||
"raw": "{{URL}}/contracts/1",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"contracts",
|
||||
"1"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Get Contracts for Buyers",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{URL}}/contracts",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"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": {
|
||||
"raw": "{{URL}}/contracts/statuses",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"contracts",
|
||||
"statuses"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "GetContractStatuses",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{URL}}/contracts/statuses",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"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": {
|
||||
"raw": "{{URL}}/product_templates/1",
|
||||
"host": [
|
||||
"{{URL}}"
|
||||
],
|
||||
"path": [
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
1732
postman/NOVA.postman_collection.json
Normal file
1732
postman/NOVA.postman_collection.json
Normal file
File diff suppressed because one or more lines are too long
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Created by VoidArtanis on 10/22/2017
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/VoidArtanis/go-rest-boilerplate/middlewares"
|
||||
"github.com/VoidArtanis/go-rest-boilerplate/controllers"
|
||||
)
|
||||
|
||||
func RegisterProtectedRoutes(r *gin.Engine){
|
||||
|
||||
authGroup := r.Group("/auth")
|
||||
|
||||
authGroup.Use(middlewares.AuthHandler("admin"))
|
||||
{
|
||||
authGroup.GET("/getmessage",controllers.GetSecretText)
|
||||
}
|
||||
}
|
||||
23
routes/protected_routes.go
Normal file
23
routes/protected_routes.go
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Created by VoidArtanis on 10/22/2017
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"gitlab.com/pactual1/backend/middlewares"
|
||||
|
||||
"gitlab.com/pactual1/backend/controllers"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterProtectedRoutes(r *gin.Engine) {
|
||||
|
||||
authGroup := r.Group("/auth")
|
||||
|
||||
authGroup.Use(middlewares.AuthHandler("admin"))
|
||||
{
|
||||
authGroup.GET("/getmessage", controllers.GetSecretText)
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Created by VoidArtanis on 10/22/2017
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/VoidArtanis/go-rest-boilerplate/controllers"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterPublicRoutes(r *gin.Engine){
|
||||
|
||||
r.GET("/publicmessage", controllers.GetPublicText)
|
||||
// r.GET("/companies", controllers.Ge)
|
||||
}
|
||||
|
||||
58
routes/public_routes.go
Normal file
58
routes/public_routes.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"gitlab.com/pactual1/backend/controllers"
|
||||
"gitlab.com/pactual1/backend/middlewares"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterPublicRoutes(r *gin.Engine) {
|
||||
|
||||
// Health checks
|
||||
r.GET("/health", controllers.HealthCheck)
|
||||
|
||||
// Map dashboard
|
||||
r.GET("/dashboard/map/contract/devices", middlewares.ContractCheckMiddleware(), middlewares.AuthMiddleware(), controllers.GetDevicesByContract)
|
||||
r.GET("/dashboard/map/contracts", middlewares.ContractCheckMiddleware(), middlewares.AuthMiddleware(), controllers.GetLatestContracts)
|
||||
r.GET("/dashboard/map/device_data", middlewares.ContractCheckMiddleware(), middlewares.AuthMiddleware(), controllers.GetDeviceData)
|
||||
|
||||
// Invoices
|
||||
r.GET("/invoices", middlewares.AuthMiddleware(), controllers.GetInvoices)
|
||||
r.GET("/invoices/:id", middlewares.AuthMiddleware(), controllers.GetInvoiceByID)
|
||||
|
||||
r.POST("/device_data/save", controllers.SaveDeviceInfo)
|
||||
r.GET("/buyers", middlewares.AuthMiddleware(), controllers.ListCompanies)
|
||||
r.GET("/products", middlewares.AuthMiddleware(), middlewares.AuthMiddleware(), controllers.ListProductTemplates)
|
||||
r.GET("/templates", middlewares.AuthMiddleware(), controllers.ListTextTemplates)
|
||||
r.POST("/templates/save", middlewares.AuthMiddleware(), controllers.CreateTextTemplate)
|
||||
r.GET("/products/:template_id", middlewares.AuthMiddleware(), controllers.GetProductTemplate)
|
||||
|
||||
// Contracts
|
||||
r.GET("/contracts/statuses", middlewares.AuthMiddleware(), controllers.GetContractStatuses)
|
||||
r.GET("/contracts", middlewares.AuthMiddleware(), controllers.GetBuyerContracts)
|
||||
r.POST("/contracts/create", middlewares.AuthMiddleware(), controllers.CreateContract)
|
||||
|
||||
r.GET("/contracts/:contract_id", middlewares.AuthMiddleware(), controllers.GetContractByID)
|
||||
r.PATCH("/contracts/:contract_id", middlewares.AuthMiddleware(), controllers.UpdateContract)
|
||||
|
||||
// Locations
|
||||
r.GET("/locations", middlewares.AuthMiddleware(), controllers.SearchPlace)
|
||||
|
||||
// Notifications
|
||||
r.GET("/notifications", middlewares.AuthMiddleware(), controllers.GetNotifications)
|
||||
|
||||
// Stats
|
||||
r.GET("/stats/measurements", middlewares.AuthMiddleware(), controllers.GetCompanyRelatedDeviceInfoCount)
|
||||
r.GET("/stats/devices", middlewares.AuthMiddleware(), controllers.GetCompanyRelatedDeviceInfoCountWithTempRange)
|
||||
r.GET("/stats/contracts", middlewares.AuthMiddleware(), controllers.GetContractCountByStatus)
|
||||
r.GET("/stats/contracts/total", middlewares.AuthMiddleware(), controllers.GetTotalContractCount)
|
||||
r.GET("/stats/invoices", middlewares.AuthMiddleware(), controllers.GetInvoiceCountByStatus)
|
||||
r.GET("/stats/milestones", middlewares.AuthMiddleware(), controllers.GetContractsMatchingDeviceLocation)
|
||||
|
||||
//Users
|
||||
r.POST("/user/reset/password", controllers.ResetPassword)
|
||||
r.POST("/user/set/password", controllers.UpdatePassword)
|
||||
r.POST("/user/login", controllers.Login)
|
||||
r.POST("/user/logout", controllers.Logout)
|
||||
}
|
||||
@@ -5,20 +5,22 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"gitlab.com/pactual1/backend/controllers"
|
||||
|
||||
"gitlab.com/pactual1/backend/middlewares"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/VoidArtanis/go-rest-boilerplate/controllers"
|
||||
"github.com/VoidArtanis/go-rest-boilerplate/middlewares"
|
||||
)
|
||||
|
||||
func InitRouter(engine *gin.Engine) {
|
||||
InitMiddleware(engine)
|
||||
authController := new(controllers.AuthController)
|
||||
engine.POST("/login", authController.HandleLogin)
|
||||
engine.POST("/login", authController.HandleLogin)
|
||||
RegisterProtectedRoutes(engine)
|
||||
RegisterPublicRoutes(engine)
|
||||
RegisterUtilityRoutes(engine)
|
||||
}
|
||||
|
||||
func InitMiddleware(engine *gin.Engine){
|
||||
engine.Use(middlewares.CORSMiddleware());
|
||||
}
|
||||
func InitMiddleware(engine *gin.Engine) {
|
||||
engine.Use(middlewares.CORSMiddleware())
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ package routes
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func RegisterUtilityRoutes(r *gin.Engine){
|
||||
func RegisterUtilityRoutes(r *gin.Engine) {
|
||||
registerRing(r)
|
||||
}
|
||||
|
||||
func registerRing(r *gin.Engine){
|
||||
func registerRing(r *gin.Engine) {
|
||||
// Ping test
|
||||
r.GET("/ping", func(c *gin.Context) {
|
||||
c.String(200, "pong")
|
||||
})
|
||||
}
|
||||
}
|
||||
770
services/blockchain/lib/contract_client.go
Normal file
770
services/blockchain/lib/contract_client.go
Normal file
@@ -0,0 +1,770 @@
|
||||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = strings.NewReader
|
||||
_ = ethereum.NotFound
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = event.NewSubscription
|
||||
_ = abi.ConvertType
|
||||
)
|
||||
|
||||
// BlockchainMetaData contains all meta data concerning the Blockchain contract.
|
||||
var BlockchainMetaData = &bind.MetaData{
|
||||
ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"deviceId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"addIOTData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"}],\"name\":\"createContract\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getContracts\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"deviceId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"}],\"name\":\"getDataByContractId\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"deviceId\",\"type\":\"bytes32\"}],\"name\":\"getDataByDeviceId\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"}],\"name\":\"getDevicesIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"deviceId\",\"type\":\"bytes32\"}],\"name\":\"getTimestampsForDevice\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"}],\"name\":\"isContractExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"deviceId\",\"type\":\"bytes32\"}],\"name\":\"isDeviceExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"deviceId\",\"type\":\"bytes32\"}],\"name\":\"registerNewDeviceId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"contractId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"_deviceIds\",\"type\":\"bytes32[]\"}],\"name\":\"registerNewDeviceIds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
|
||||
}
|
||||
|
||||
// BlockchainABI is the input ABI used to generate the binding from.
|
||||
// Deprecated: Use BlockchainMetaData.ABI instead.
|
||||
var BlockchainABI = BlockchainMetaData.ABI
|
||||
|
||||
// Blockchain is an auto generated Go binding around an Ethereum contract.
|
||||
type Blockchain struct {
|
||||
BlockchainCaller // Read-only binding to the contract
|
||||
BlockchainTransactor // Write-only binding to the contract
|
||||
BlockchainFilterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// BlockchainCaller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type BlockchainCaller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// BlockchainTransactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type BlockchainTransactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// BlockchainFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type BlockchainFilterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// BlockchainSession is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type BlockchainSession struct {
|
||||
Contract *Blockchain // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// BlockchainCallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type BlockchainCallerSession struct {
|
||||
Contract *BlockchainCaller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// BlockchainTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type BlockchainTransactorSession struct {
|
||||
Contract *BlockchainTransactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// BlockchainRaw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type BlockchainRaw struct {
|
||||
Contract *Blockchain // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// BlockchainCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type BlockchainCallerRaw struct {
|
||||
Contract *BlockchainCaller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// BlockchainTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type BlockchainTransactorRaw struct {
|
||||
Contract *BlockchainTransactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// NewBlockchain creates a new instance of Blockchain, bound to a specific deployed contract.
|
||||
func NewBlockchain(address common.Address, backend bind.ContractBackend) (*Blockchain, error) {
|
||||
contract, err := bindBlockchain(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Blockchain{BlockchainCaller: BlockchainCaller{contract: contract}, BlockchainTransactor: BlockchainTransactor{contract: contract}, BlockchainFilterer: BlockchainFilterer{contract: contract}}, nil
|
||||
}
|
||||
|
||||
// NewBlockchainCaller creates a new read-only instance of Blockchain, bound to a specific deployed contract.
|
||||
func NewBlockchainCaller(address common.Address, caller bind.ContractCaller) (*BlockchainCaller, error) {
|
||||
contract, err := bindBlockchain(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BlockchainCaller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewBlockchainTransactor creates a new write-only instance of Blockchain, bound to a specific deployed contract.
|
||||
func NewBlockchainTransactor(address common.Address, transactor bind.ContractTransactor) (*BlockchainTransactor, error) {
|
||||
contract, err := bindBlockchain(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BlockchainTransactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewBlockchainFilterer creates a new log filterer instance of Blockchain, bound to a specific deployed contract.
|
||||
func NewBlockchainFilterer(address common.Address, filterer bind.ContractFilterer) (*BlockchainFilterer, error) {
|
||||
contract, err := bindBlockchain(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BlockchainFilterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bindBlockchain binds a generic wrapper to an already deployed contract.
|
||||
func bindBlockchain(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := BlockchainMetaData.GetAbi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_Blockchain *BlockchainRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _Blockchain.Contract.BlockchainCaller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_Blockchain *BlockchainRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.BlockchainTransactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_Blockchain *BlockchainRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.BlockchainTransactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_Blockchain *BlockchainCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _Blockchain.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_Blockchain *BlockchainTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_Blockchain *BlockchainTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// GetContracts is a free data retrieval call binding the contract method 0xc3a2a93a.
|
||||
//
|
||||
// Solidity: function getContracts() view returns(bytes32[])
|
||||
func (_Blockchain *BlockchainCaller) GetContracts(opts *bind.CallOpts) ([][32]byte, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "getContracts")
|
||||
|
||||
if err != nil {
|
||||
return *new([][32]byte), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// GetContracts is a free data retrieval call binding the contract method 0xc3a2a93a.
|
||||
//
|
||||
// Solidity: function getContracts() view returns(bytes32[])
|
||||
func (_Blockchain *BlockchainSession) GetContracts() ([][32]byte, error) {
|
||||
return _Blockchain.Contract.GetContracts(&_Blockchain.CallOpts)
|
||||
}
|
||||
|
||||
// GetContracts is a free data retrieval call binding the contract method 0xc3a2a93a.
|
||||
//
|
||||
// Solidity: function getContracts() view returns(bytes32[])
|
||||
func (_Blockchain *BlockchainCallerSession) GetContracts() ([][32]byte, error) {
|
||||
return _Blockchain.Contract.GetContracts(&_Blockchain.CallOpts)
|
||||
}
|
||||
|
||||
// GetData is a free data retrieval call binding the contract method 0x164b2f16.
|
||||
//
|
||||
// Solidity: function getData(bytes32 contractId, bytes32 deviceId, uint256 timestamp) view returns(bytes)
|
||||
func (_Blockchain *BlockchainCaller) GetData(opts *bind.CallOpts, contractId [32]byte, deviceId [32]byte, timestamp *big.Int) ([]byte, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "getData", contractId, deviceId, timestamp)
|
||||
|
||||
if err != nil {
|
||||
return *new([]byte), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// GetData is a free data retrieval call binding the contract method 0x164b2f16.
|
||||
//
|
||||
// Solidity: function getData(bytes32 contractId, bytes32 deviceId, uint256 timestamp) view returns(bytes)
|
||||
func (_Blockchain *BlockchainSession) GetData(contractId [32]byte, deviceId [32]byte, timestamp *big.Int) ([]byte, error) {
|
||||
return _Blockchain.Contract.GetData(&_Blockchain.CallOpts, contractId, deviceId, timestamp)
|
||||
}
|
||||
|
||||
// GetData is a free data retrieval call binding the contract method 0x164b2f16.
|
||||
//
|
||||
// Solidity: function getData(bytes32 contractId, bytes32 deviceId, uint256 timestamp) view returns(bytes)
|
||||
func (_Blockchain *BlockchainCallerSession) GetData(contractId [32]byte, deviceId [32]byte, timestamp *big.Int) ([]byte, error) {
|
||||
return _Blockchain.Contract.GetData(&_Blockchain.CallOpts, contractId, deviceId, timestamp)
|
||||
}
|
||||
|
||||
// GetDataByContractId is a free data retrieval call binding the contract method 0xc3dfe0be.
|
||||
//
|
||||
// Solidity: function getDataByContractId(bytes32 contractId) view returns(bytes _data)
|
||||
func (_Blockchain *BlockchainCaller) GetDataByContractId(opts *bind.CallOpts, contractId [32]byte) ([]byte, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "getDataByContractId", contractId)
|
||||
|
||||
if err != nil {
|
||||
return *new([]byte), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// GetDataByContractId is a free data retrieval call binding the contract method 0xc3dfe0be.
|
||||
//
|
||||
// Solidity: function getDataByContractId(bytes32 contractId) view returns(bytes _data)
|
||||
func (_Blockchain *BlockchainSession) GetDataByContractId(contractId [32]byte) ([]byte, error) {
|
||||
return _Blockchain.Contract.GetDataByContractId(&_Blockchain.CallOpts, contractId)
|
||||
}
|
||||
|
||||
// GetDataByContractId is a free data retrieval call binding the contract method 0xc3dfe0be.
|
||||
//
|
||||
// Solidity: function getDataByContractId(bytes32 contractId) view returns(bytes _data)
|
||||
func (_Blockchain *BlockchainCallerSession) GetDataByContractId(contractId [32]byte) ([]byte, error) {
|
||||
return _Blockchain.Contract.GetDataByContractId(&_Blockchain.CallOpts, contractId)
|
||||
}
|
||||
|
||||
// GetDataByDeviceId is a free data retrieval call binding the contract method 0x7e0411dc.
|
||||
//
|
||||
// Solidity: function getDataByDeviceId(bytes32 contractId, bytes32 deviceId) view returns(bytes _data)
|
||||
func (_Blockchain *BlockchainCaller) GetDataByDeviceId(opts *bind.CallOpts, contractId [32]byte, deviceId [32]byte) ([]byte, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "getDataByDeviceId", contractId, deviceId)
|
||||
|
||||
if err != nil {
|
||||
return *new([]byte), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// GetDataByDeviceId is a free data retrieval call binding the contract method 0x7e0411dc.
|
||||
//
|
||||
// Solidity: function getDataByDeviceId(bytes32 contractId, bytes32 deviceId) view returns(bytes _data)
|
||||
func (_Blockchain *BlockchainSession) GetDataByDeviceId(contractId [32]byte, deviceId [32]byte) ([]byte, error) {
|
||||
return _Blockchain.Contract.GetDataByDeviceId(&_Blockchain.CallOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// GetDataByDeviceId is a free data retrieval call binding the contract method 0x7e0411dc.
|
||||
//
|
||||
// Solidity: function getDataByDeviceId(bytes32 contractId, bytes32 deviceId) view returns(bytes _data)
|
||||
func (_Blockchain *BlockchainCallerSession) GetDataByDeviceId(contractId [32]byte, deviceId [32]byte) ([]byte, error) {
|
||||
return _Blockchain.Contract.GetDataByDeviceId(&_Blockchain.CallOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// GetDevicesIds is a free data retrieval call binding the contract method 0xc0789e40.
|
||||
//
|
||||
// Solidity: function getDevicesIds(bytes32 contractId) view returns(bytes32[])
|
||||
func (_Blockchain *BlockchainCaller) GetDevicesIds(opts *bind.CallOpts, contractId [32]byte) ([][32]byte, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "getDevicesIds", contractId)
|
||||
|
||||
if err != nil {
|
||||
return *new([][32]byte), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// GetDevicesIds is a free data retrieval call binding the contract method 0xc0789e40.
|
||||
//
|
||||
// Solidity: function getDevicesIds(bytes32 contractId) view returns(bytes32[])
|
||||
func (_Blockchain *BlockchainSession) GetDevicesIds(contractId [32]byte) ([][32]byte, error) {
|
||||
return _Blockchain.Contract.GetDevicesIds(&_Blockchain.CallOpts, contractId)
|
||||
}
|
||||
|
||||
// GetDevicesIds is a free data retrieval call binding the contract method 0xc0789e40.
|
||||
//
|
||||
// Solidity: function getDevicesIds(bytes32 contractId) view returns(bytes32[])
|
||||
func (_Blockchain *BlockchainCallerSession) GetDevicesIds(contractId [32]byte) ([][32]byte, error) {
|
||||
return _Blockchain.Contract.GetDevicesIds(&_Blockchain.CallOpts, contractId)
|
||||
}
|
||||
|
||||
// GetTimestampsForDevice is a free data retrieval call binding the contract method 0x6254aad3.
|
||||
//
|
||||
// Solidity: function getTimestampsForDevice(bytes32 contractId, bytes32 deviceId) view returns(uint256[])
|
||||
func (_Blockchain *BlockchainCaller) GetTimestampsForDevice(opts *bind.CallOpts, contractId [32]byte, deviceId [32]byte) ([]*big.Int, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "getTimestampsForDevice", contractId, deviceId)
|
||||
|
||||
if err != nil {
|
||||
return *new([]*big.Int), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// GetTimestampsForDevice is a free data retrieval call binding the contract method 0x6254aad3.
|
||||
//
|
||||
// Solidity: function getTimestampsForDevice(bytes32 contractId, bytes32 deviceId) view returns(uint256[])
|
||||
func (_Blockchain *BlockchainSession) GetTimestampsForDevice(contractId [32]byte, deviceId [32]byte) ([]*big.Int, error) {
|
||||
return _Blockchain.Contract.GetTimestampsForDevice(&_Blockchain.CallOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// GetTimestampsForDevice is a free data retrieval call binding the contract method 0x6254aad3.
|
||||
//
|
||||
// Solidity: function getTimestampsForDevice(bytes32 contractId, bytes32 deviceId) view returns(uint256[])
|
||||
func (_Blockchain *BlockchainCallerSession) GetTimestampsForDevice(contractId [32]byte, deviceId [32]byte) ([]*big.Int, error) {
|
||||
return _Blockchain.Contract.GetTimestampsForDevice(&_Blockchain.CallOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// IsContractExists is a free data retrieval call binding the contract method 0x0eb18461.
|
||||
//
|
||||
// Solidity: function isContractExists(bytes32 contractId) view returns(bool)
|
||||
func (_Blockchain *BlockchainCaller) IsContractExists(opts *bind.CallOpts, contractId [32]byte) (bool, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "isContractExists", contractId)
|
||||
|
||||
if err != nil {
|
||||
return *new(bool), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// IsContractExists is a free data retrieval call binding the contract method 0x0eb18461.
|
||||
//
|
||||
// Solidity: function isContractExists(bytes32 contractId) view returns(bool)
|
||||
func (_Blockchain *BlockchainSession) IsContractExists(contractId [32]byte) (bool, error) {
|
||||
return _Blockchain.Contract.IsContractExists(&_Blockchain.CallOpts, contractId)
|
||||
}
|
||||
|
||||
// IsContractExists is a free data retrieval call binding the contract method 0x0eb18461.
|
||||
//
|
||||
// Solidity: function isContractExists(bytes32 contractId) view returns(bool)
|
||||
func (_Blockchain *BlockchainCallerSession) IsContractExists(contractId [32]byte) (bool, error) {
|
||||
return _Blockchain.Contract.IsContractExists(&_Blockchain.CallOpts, contractId)
|
||||
}
|
||||
|
||||
// IsDeviceExists is a free data retrieval call binding the contract method 0xba12b630.
|
||||
//
|
||||
// Solidity: function isDeviceExists(bytes32 contractId, bytes32 deviceId) view returns(bool)
|
||||
func (_Blockchain *BlockchainCaller) IsDeviceExists(opts *bind.CallOpts, contractId [32]byte, deviceId [32]byte) (bool, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "isDeviceExists", contractId, deviceId)
|
||||
|
||||
if err != nil {
|
||||
return *new(bool), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// IsDeviceExists is a free data retrieval call binding the contract method 0xba12b630.
|
||||
//
|
||||
// Solidity: function isDeviceExists(bytes32 contractId, bytes32 deviceId) view returns(bool)
|
||||
func (_Blockchain *BlockchainSession) IsDeviceExists(contractId [32]byte, deviceId [32]byte) (bool, error) {
|
||||
return _Blockchain.Contract.IsDeviceExists(&_Blockchain.CallOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// IsDeviceExists is a free data retrieval call binding the contract method 0xba12b630.
|
||||
//
|
||||
// Solidity: function isDeviceExists(bytes32 contractId, bytes32 deviceId) view returns(bool)
|
||||
func (_Blockchain *BlockchainCallerSession) IsDeviceExists(contractId [32]byte, deviceId [32]byte) (bool, error) {
|
||||
return _Blockchain.Contract.IsDeviceExists(&_Blockchain.CallOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// Owner is a free data retrieval call binding the contract method 0x8da5cb5b.
|
||||
//
|
||||
// Solidity: function owner() view returns(address)
|
||||
func (_Blockchain *BlockchainCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "owner")
|
||||
|
||||
if err != nil {
|
||||
return *new(common.Address), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// Owner is a free data retrieval call binding the contract method 0x8da5cb5b.
|
||||
//
|
||||
// Solidity: function owner() view returns(address)
|
||||
func (_Blockchain *BlockchainSession) Owner() (common.Address, error) {
|
||||
return _Blockchain.Contract.Owner(&_Blockchain.CallOpts)
|
||||
}
|
||||
|
||||
// Owner is a free data retrieval call binding the contract method 0x8da5cb5b.
|
||||
//
|
||||
// Solidity: function owner() view returns(address)
|
||||
func (_Blockchain *BlockchainCallerSession) Owner() (common.Address, error) {
|
||||
return _Blockchain.Contract.Owner(&_Blockchain.CallOpts)
|
||||
}
|
||||
|
||||
// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7.
|
||||
//
|
||||
// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool)
|
||||
func (_Blockchain *BlockchainCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
|
||||
var out []interface{}
|
||||
err := _Blockchain.contract.Call(opts, &out, "supportsInterface", interfaceId)
|
||||
|
||||
if err != nil {
|
||||
return *new(bool), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7.
|
||||
//
|
||||
// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool)
|
||||
func (_Blockchain *BlockchainSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
|
||||
return _Blockchain.Contract.SupportsInterface(&_Blockchain.CallOpts, interfaceId)
|
||||
}
|
||||
|
||||
// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7.
|
||||
//
|
||||
// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool)
|
||||
func (_Blockchain *BlockchainCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
|
||||
return _Blockchain.Contract.SupportsInterface(&_Blockchain.CallOpts, interfaceId)
|
||||
}
|
||||
|
||||
// AddIOTData is a paid mutator transaction binding the contract method 0x5d76f5c9.
|
||||
//
|
||||
// Solidity: function addIOTData(bytes32 contractId, bytes32 deviceId, uint256 timestamp, bytes _data) returns()
|
||||
func (_Blockchain *BlockchainTransactor) AddIOTData(opts *bind.TransactOpts, contractId [32]byte, deviceId [32]byte, timestamp *big.Int, _data []byte) (*types.Transaction, error) {
|
||||
return _Blockchain.contract.Transact(opts, "addIOTData", contractId, deviceId, timestamp, _data)
|
||||
}
|
||||
|
||||
// AddIOTData is a paid mutator transaction binding the contract method 0x5d76f5c9.
|
||||
//
|
||||
// Solidity: function addIOTData(bytes32 contractId, bytes32 deviceId, uint256 timestamp, bytes _data) returns()
|
||||
func (_Blockchain *BlockchainSession) AddIOTData(contractId [32]byte, deviceId [32]byte, timestamp *big.Int, _data []byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.AddIOTData(&_Blockchain.TransactOpts, contractId, deviceId, timestamp, _data)
|
||||
}
|
||||
|
||||
// AddIOTData is a paid mutator transaction binding the contract method 0x5d76f5c9.
|
||||
//
|
||||
// Solidity: function addIOTData(bytes32 contractId, bytes32 deviceId, uint256 timestamp, bytes _data) returns()
|
||||
func (_Blockchain *BlockchainTransactorSession) AddIOTData(contractId [32]byte, deviceId [32]byte, timestamp *big.Int, _data []byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.AddIOTData(&_Blockchain.TransactOpts, contractId, deviceId, timestamp, _data)
|
||||
}
|
||||
|
||||
// CreateContract is a paid mutator transaction binding the contract method 0x3f811b80.
|
||||
//
|
||||
// Solidity: function createContract(bytes32 contractId) returns()
|
||||
func (_Blockchain *BlockchainTransactor) CreateContract(opts *bind.TransactOpts, contractId [32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.contract.Transact(opts, "createContract", contractId)
|
||||
}
|
||||
|
||||
// CreateContract is a paid mutator transaction binding the contract method 0x3f811b80.
|
||||
//
|
||||
// Solidity: function createContract(bytes32 contractId) returns()
|
||||
func (_Blockchain *BlockchainSession) CreateContract(contractId [32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.CreateContract(&_Blockchain.TransactOpts, contractId)
|
||||
}
|
||||
|
||||
// CreateContract is a paid mutator transaction binding the contract method 0x3f811b80.
|
||||
//
|
||||
// Solidity: function createContract(bytes32 contractId) returns()
|
||||
func (_Blockchain *BlockchainTransactorSession) CreateContract(contractId [32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.CreateContract(&_Blockchain.TransactOpts, contractId)
|
||||
}
|
||||
|
||||
// RegisterNewDeviceId is a paid mutator transaction binding the contract method 0x73b5a2e6.
|
||||
//
|
||||
// Solidity: function registerNewDeviceId(bytes32 contractId, bytes32 deviceId) returns()
|
||||
func (_Blockchain *BlockchainTransactor) RegisterNewDeviceId(opts *bind.TransactOpts, contractId [32]byte, deviceId [32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.contract.Transact(opts, "registerNewDeviceId", contractId, deviceId)
|
||||
}
|
||||
|
||||
// RegisterNewDeviceId is a paid mutator transaction binding the contract method 0x73b5a2e6.
|
||||
//
|
||||
// Solidity: function registerNewDeviceId(bytes32 contractId, bytes32 deviceId) returns()
|
||||
func (_Blockchain *BlockchainSession) RegisterNewDeviceId(contractId [32]byte, deviceId [32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.RegisterNewDeviceId(&_Blockchain.TransactOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// RegisterNewDeviceId is a paid mutator transaction binding the contract method 0x73b5a2e6.
|
||||
//
|
||||
// Solidity: function registerNewDeviceId(bytes32 contractId, bytes32 deviceId) returns()
|
||||
func (_Blockchain *BlockchainTransactorSession) RegisterNewDeviceId(contractId [32]byte, deviceId [32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.RegisterNewDeviceId(&_Blockchain.TransactOpts, contractId, deviceId)
|
||||
}
|
||||
|
||||
// RegisterNewDeviceIds is a paid mutator transaction binding the contract method 0xec9e8a8e.
|
||||
//
|
||||
// Solidity: function registerNewDeviceIds(bytes32 contractId, bytes32[] _deviceIds) returns()
|
||||
func (_Blockchain *BlockchainTransactor) RegisterNewDeviceIds(opts *bind.TransactOpts, contractId [32]byte, _deviceIds [][32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.contract.Transact(opts, "registerNewDeviceIds", contractId, _deviceIds)
|
||||
}
|
||||
|
||||
// RegisterNewDeviceIds is a paid mutator transaction binding the contract method 0xec9e8a8e.
|
||||
//
|
||||
// Solidity: function registerNewDeviceIds(bytes32 contractId, bytes32[] _deviceIds) returns()
|
||||
func (_Blockchain *BlockchainSession) RegisterNewDeviceIds(contractId [32]byte, _deviceIds [][32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.RegisterNewDeviceIds(&_Blockchain.TransactOpts, contractId, _deviceIds)
|
||||
}
|
||||
|
||||
// RegisterNewDeviceIds is a paid mutator transaction binding the contract method 0xec9e8a8e.
|
||||
//
|
||||
// Solidity: function registerNewDeviceIds(bytes32 contractId, bytes32[] _deviceIds) returns()
|
||||
func (_Blockchain *BlockchainTransactorSession) RegisterNewDeviceIds(contractId [32]byte, _deviceIds [][32]byte) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.RegisterNewDeviceIds(&_Blockchain.TransactOpts, contractId, _deviceIds)
|
||||
}
|
||||
|
||||
// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6.
|
||||
//
|
||||
// Solidity: function renounceOwnership() returns()
|
||||
func (_Blockchain *BlockchainTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _Blockchain.contract.Transact(opts, "renounceOwnership")
|
||||
}
|
||||
|
||||
// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6.
|
||||
//
|
||||
// Solidity: function renounceOwnership() returns()
|
||||
func (_Blockchain *BlockchainSession) RenounceOwnership() (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.RenounceOwnership(&_Blockchain.TransactOpts)
|
||||
}
|
||||
|
||||
// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6.
|
||||
//
|
||||
// Solidity: function renounceOwnership() returns()
|
||||
func (_Blockchain *BlockchainTransactorSession) RenounceOwnership() (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.RenounceOwnership(&_Blockchain.TransactOpts)
|
||||
}
|
||||
|
||||
// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b.
|
||||
//
|
||||
// Solidity: function transferOwnership(address newOwner) returns()
|
||||
func (_Blockchain *BlockchainTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) {
|
||||
return _Blockchain.contract.Transact(opts, "transferOwnership", newOwner)
|
||||
}
|
||||
|
||||
// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b.
|
||||
//
|
||||
// Solidity: function transferOwnership(address newOwner) returns()
|
||||
func (_Blockchain *BlockchainSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.TransferOwnership(&_Blockchain.TransactOpts, newOwner)
|
||||
}
|
||||
|
||||
// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b.
|
||||
//
|
||||
// Solidity: function transferOwnership(address newOwner) returns()
|
||||
func (_Blockchain *BlockchainTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) {
|
||||
return _Blockchain.Contract.TransferOwnership(&_Blockchain.TransactOpts, newOwner)
|
||||
}
|
||||
|
||||
// BlockchainOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Blockchain contract.
|
||||
type BlockchainOwnershipTransferredIterator struct {
|
||||
Event *BlockchainOwnershipTransferred // Event containing the contract specifics and raw log
|
||||
|
||||
contract *bind.BoundContract // Generic contract to use for unpacking event data
|
||||
event string // Event name to use for unpacking event data
|
||||
|
||||
logs chan types.Log // Log channel receiving the found contract events
|
||||
sub ethereum.Subscription // Subscription for errors, completion and termination
|
||||
done bool // Whether the subscription completed delivering logs
|
||||
fail error // Occurred error to stop iteration
|
||||
}
|
||||
|
||||
// Next advances the iterator to the subsequent event, returning whether there
|
||||
// are any more events found. In case of a retrieval or parsing error, false is
|
||||
// returned and Error() can be queried for the exact failure.
|
||||
func (it *BlockchainOwnershipTransferredIterator) Next() bool {
|
||||
// If the iterator failed, stop iterating
|
||||
if it.fail != nil {
|
||||
return false
|
||||
}
|
||||
// If the iterator completed, deliver directly whatever's available
|
||||
if it.done {
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new(BlockchainOwnershipTransferred)
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Iterator still in progress, wait for either a data or an error event
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new(BlockchainOwnershipTransferred)
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
case err := <-it.sub.Err():
|
||||
it.done = true
|
||||
it.fail = err
|
||||
return it.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns any retrieval or parsing error occurred during filtering.
|
||||
func (it *BlockchainOwnershipTransferredIterator) Error() error {
|
||||
return it.fail
|
||||
}
|
||||
|
||||
// Close terminates the iteration process, releasing any pending underlying
|
||||
// resources.
|
||||
func (it *BlockchainOwnershipTransferredIterator) Close() error {
|
||||
it.sub.Unsubscribe()
|
||||
return nil
|
||||
}
|
||||
|
||||
// BlockchainOwnershipTransferred represents a OwnershipTransferred event raised by the Blockchain contract.
|
||||
type BlockchainOwnershipTransferred struct {
|
||||
PreviousOwner common.Address
|
||||
NewOwner common.Address
|
||||
Raw types.Log // Blockchain specific contextual infos
|
||||
}
|
||||
|
||||
// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0.
|
||||
//
|
||||
// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
func (_Blockchain *BlockchainFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*BlockchainOwnershipTransferredIterator, error) {
|
||||
|
||||
var previousOwnerRule []interface{}
|
||||
for _, previousOwnerItem := range previousOwner {
|
||||
previousOwnerRule = append(previousOwnerRule, previousOwnerItem)
|
||||
}
|
||||
var newOwnerRule []interface{}
|
||||
for _, newOwnerItem := range newOwner {
|
||||
newOwnerRule = append(newOwnerRule, newOwnerItem)
|
||||
}
|
||||
|
||||
logs, sub, err := _Blockchain.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BlockchainOwnershipTransferredIterator{contract: _Blockchain.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
|
||||
}
|
||||
|
||||
// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0.
|
||||
//
|
||||
// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
func (_Blockchain *BlockchainFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BlockchainOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) {
|
||||
|
||||
var previousOwnerRule []interface{}
|
||||
for _, previousOwnerItem := range previousOwner {
|
||||
previousOwnerRule = append(previousOwnerRule, previousOwnerItem)
|
||||
}
|
||||
var newOwnerRule []interface{}
|
||||
for _, newOwnerItem := range newOwner {
|
||||
newOwnerRule = append(newOwnerRule, newOwnerItem)
|
||||
}
|
||||
|
||||
logs, sub, err := _Blockchain.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
defer sub.Unsubscribe()
|
||||
for {
|
||||
select {
|
||||
case log := <-logs:
|
||||
// New log arrived, parse the event and forward to the user
|
||||
event := new(BlockchainOwnershipTransferred)
|
||||
if err := _Blockchain.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Raw = log
|
||||
|
||||
select {
|
||||
case sink <- event:
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}), nil
|
||||
}
|
||||
|
||||
// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0.
|
||||
//
|
||||
// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
|
||||
func (_Blockchain *BlockchainFilterer) ParseOwnershipTransferred(log types.Log) (*BlockchainOwnershipTransferred, error) {
|
||||
event := new(BlockchainOwnershipTransferred)
|
||||
if err := _Blockchain.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
event.Raw = log
|
||||
return event, nil
|
||||
}
|
||||
132
services/blockchain/service.go
Normal file
132
services/blockchain/service.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
blockchain "gitlab.com/pactual1/backend/services/blockchain/lib"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
networkEndpoint string
|
||||
contractAddress string
|
||||
walletAddress string
|
||||
walletPrivateKey string
|
||||
chainID big.Int
|
||||
}
|
||||
|
||||
func NewService(blockchainConfig config.Blockchain) Service {
|
||||
return &service{networkEndpoint: blockchainConfig.NetworkEndpoint, contractAddress: blockchainConfig.ContractAddress, walletAddress: blockchainConfig.WalletAddress, walletPrivateKey: blockchainConfig.WalletPrivateKey}
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
CreateContract(ctx context.Context, contractID [32]byte) error
|
||||
AddIOTData(ctx context.Context, contractID [32]byte, deviceID [32]byte, timestamp *big.Int, data []byte) error
|
||||
RegisterNewDeviceID(ctx context.Context, contractID [32]byte, deviceID [32]byte) error
|
||||
}
|
||||
|
||||
func (s *service) signerFunc(address common.Address, txn *types.Transaction) (*types.Transaction, error) {
|
||||
signer := types.NewLondonSigner(&s.chainID)
|
||||
privateKey, err := crypto.HexToECDSA(s.walletPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.SignTx(txn, signer, privateKey)
|
||||
}
|
||||
|
||||
func (s *service) getTransactOpts() *bind.TransactOpts {
|
||||
return &bind.TransactOpts{
|
||||
From: common.HexToAddress(s.walletAddress),
|
||||
Signer: s.signerFunc,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) getClient(ctx context.Context) (*ethclient.Client, *blockchain.Blockchain, error) {
|
||||
// connect to polygon network
|
||||
conn, err := ethclient.Dial(s.networkEndpoint)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// create contract client
|
||||
contract, err := blockchain.NewBlockchain(common.HexToAddress(s.contractAddress), conn)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
chainID, err := conn.ChainID(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
s.chainID = *chainID
|
||||
return conn, contract, nil
|
||||
}
|
||||
|
||||
// track transaction to handle failure in go routine
|
||||
func (s *service) trackTransaction(txn *types.Transaction, conn *ethclient.Client) {
|
||||
receipt, err := bind.WaitMined(context.Background(), conn, txn)
|
||||
defer conn.Close()
|
||||
if err != nil {
|
||||
log.Error("blockchain transaction failed with error", "error", err.Error())
|
||||
}
|
||||
|
||||
if receipt.Status != types.ReceiptStatusSuccessful {
|
||||
log.Error("blockchain transaction not successful")
|
||||
}
|
||||
}
|
||||
|
||||
// create contract with blockchain contract ID
|
||||
func (s *service) CreateContract(ctx context.Context, contractID [32]byte) error {
|
||||
conn, contract, err := s.getClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txn, err := contract.CreateContract(s.getTransactOpts(), contractID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.trackTransaction(txn, conn)
|
||||
return nil
|
||||
}
|
||||
|
||||
// map devices with blockchain contract
|
||||
func (s *service) RegisterNewDeviceID(ctx context.Context, contractID [32]byte, deviceID [32]byte) error {
|
||||
conn, contract, err := s.getClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txn, err := contract.RegisterNewDeviceId(s.getTransactOpts(), contractID, deviceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.trackTransaction(txn, conn)
|
||||
return nil
|
||||
}
|
||||
|
||||
// store device data with blockchain contract
|
||||
func (s *service) AddIOTData(ctx context.Context, contractID [32]byte, deviceID [32]byte, timestamp *big.Int, data []byte) error {
|
||||
conn, contract, err := s.getClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txn, err := contract.AddIOTData(s.getTransactOpts(), contractID, deviceID, timestamp, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.trackTransaction(txn, conn)
|
||||
return nil
|
||||
}
|
||||
31
services/contract/contract_service.go
Normal file
31
services/contract/contract_service.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package contract
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/services/blockchain"
|
||||
"gitlab.com/pactual1/backend/shared"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
ch chan string
|
||||
db *gorm.DB
|
||||
encryptionClient shared.EncryptionClient
|
||||
blockchainClient blockchain.Service
|
||||
}
|
||||
|
||||
func NewService(ch chan string, db *gorm.DB, encryptionClient shared.EncryptionClient, blockchainClient blockchain.Service) service {
|
||||
return service{
|
||||
ch: ch,
|
||||
db: db,
|
||||
encryptionClient: encryptionClient,
|
||||
blockchainClient: blockchainClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (s service) ContractService() {
|
||||
for msg := range s.ch {
|
||||
fmt.Println("Contract Service: ", msg)
|
||||
}
|
||||
}
|
||||
11
services/erp/erp_service.go
Normal file
11
services/erp/erp_service.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package erp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ERPService(ch chan string) {
|
||||
for msg := range ch {
|
||||
fmt.Println("ERP Service: ", msg)
|
||||
}
|
||||
}
|
||||
33
services/location/location_service.go
Normal file
33
services/location/location_service.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package location
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
"gitlab.com/pactual1/backend/services/location/mapbox_lib"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
accessToken string
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
SearchPlace(context.Context, string) ([]*models.Place, error)
|
||||
}
|
||||
|
||||
func NewService(accessToken string) Service {
|
||||
return service{accessToken: accessToken}
|
||||
}
|
||||
|
||||
func (s service) SearchPlace(ctx context.Context, query string) ([]*models.Place, error) {
|
||||
geocoder := mapbox.NewFastHttpGeocoder(mapbox.AccessToken(s.accessToken))
|
||||
resp, err := geocoder.ForwardGeocode(ctx, &mapbox.ForwardGeocodeRequest{SearchText: query})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var places []*models.Place
|
||||
for _, feature := range resp.Features {
|
||||
places = append(places, &models.Place{Text: feature.Text, Coordinates: feature.Geometry.Coordinates})
|
||||
}
|
||||
return places, nil
|
||||
}
|
||||
7
services/location/mapbox_lib/client.go
Normal file
7
services/location/mapbox_lib/client.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package mapbox
|
||||
|
||||
// Client covers all Mabpox API
|
||||
type Client interface {
|
||||
// Geocoder covers forward and reverse geocoding mapbox API
|
||||
Geocoder
|
||||
}
|
||||
103
services/location/mapbox_lib/config.go
Normal file
103
services/location/mapbox_lib/config.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAPI = "https://api.mapbox.com"
|
||||
)
|
||||
|
||||
// Option allows gradually modify config
|
||||
type Option func(c config) config
|
||||
|
||||
type config struct {
|
||||
accessToken string
|
||||
rootAPI string
|
||||
client FastHttpClient
|
||||
logger Logger
|
||||
// requestLogger will be called instead of testLogger if set.
|
||||
requestLogger func(ctx context.Context) Logger
|
||||
|
||||
accessTokenGetValue []byte
|
||||
geocodeEndpoint string
|
||||
}
|
||||
|
||||
// withEnv overwrites config values with env is not empty
|
||||
func (c config) withEnv() config {
|
||||
at := os.Getenv("MAPBOX_ACCESS_TOKEN")
|
||||
if at != "" {
|
||||
c.accessToken = at
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// prepare prebuilds some reused api parts like access token http get value
|
||||
func (c config) prepare() config {
|
||||
c.accessTokenGetValue = []byte(questionMark + access_token + string(equalMark) + c.accessToken)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func newConfig() config {
|
||||
return config{
|
||||
rootAPI: defaultAPI,
|
||||
client: &fasthttp.Client{},
|
||||
geocodeEndpoint: "mapbox.places",
|
||||
}
|
||||
}
|
||||
|
||||
// Log used to debug traces and to log errors.
|
||||
func Log(l Logger) Option {
|
||||
return func(c config) config {
|
||||
c.logger = l
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
// RequestLogger sets the way testLogger could be extracted from request context.
|
||||
// If set will be used instead of Log.
|
||||
func RequestLogger(extract func(ctx context.Context) Logger) Option {
|
||||
return func(c config) config {
|
||||
c.requestLogger = extract
|
||||
return c
|
||||
}
|
||||
}
|
||||
// AccessToken sets access_token get param.
|
||||
// Could be set with MAPBOX_ACCESS_TOKEN too.
|
||||
func AccessToken(at string) Option {
|
||||
return func(c config) config {
|
||||
c.accessToken = at
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
// RootAPI allows to change root api address.
|
||||
// default to https://api.mapbox.com
|
||||
func RootAPI(rootAPI string) Option {
|
||||
return func(c config) config {
|
||||
c.rootAPI = rootAPI
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
// HttpClient allows to change default fast http client
|
||||
func HttpClient(c FastHttpClient) Option {
|
||||
return func(fhc config) config {
|
||||
fhc.client = c
|
||||
return fhc
|
||||
}
|
||||
}
|
||||
|
||||
// GeocodeEndpoint sets geocode endpoint.
|
||||
// could be set to mapbox.places-permanent, defualt to mapbox.places
|
||||
func GeocodeEndpoint(endpoint string) Option {
|
||||
return func(c config) config {
|
||||
c.geocodeEndpoint = endpoint
|
||||
return c
|
||||
}
|
||||
}
|
||||
35
services/location/mapbox_lib/entities.go
Normal file
35
services/location/mapbox_lib/entities.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package mapbox
|
||||
|
||||
type (
|
||||
Feature struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
PlaceType []string `json:"place_type"`
|
||||
Relevance float64 `json:"relevance"`
|
||||
Properties Properties `json:"properties"`
|
||||
Text string `json:"text"`
|
||||
PlaceName string `json:"place_name"`
|
||||
Center []float64 `json:"center"`
|
||||
Geometry Geometry `json:"geometry"`
|
||||
Address string `json:"address"`
|
||||
Context []Context `json:"context"`
|
||||
BoundingBox []float64 `json:"bbox"`
|
||||
}
|
||||
|
||||
Properties struct {
|
||||
Accuracy string `json:"accuracy"`
|
||||
ShortCode string `json:"short_code"`
|
||||
}
|
||||
|
||||
Geometry struct {
|
||||
Type string `json:"type"`
|
||||
Coordinates []float64 `json:"coordinates"`
|
||||
}
|
||||
|
||||
Context struct {
|
||||
ID string `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Wikidata string `json:"wikidata"`
|
||||
ShortCode string `json:"short_code"`
|
||||
}
|
||||
)
|
||||
555
services/location/mapbox_lib/entities_easyjson.go
Normal file
555
services/location/mapbox_lib/entities_easyjson.go
Normal file
@@ -0,0 +1,555 @@
|
||||
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
|
||||
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
easyjson "github.com/mailru/easyjson"
|
||||
jlexer "github.com/mailru/easyjson/jlexer"
|
||||
jwriter "github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
// suppress unused package warning
|
||||
var (
|
||||
_ *json.RawMessage
|
||||
_ *jlexer.Lexer
|
||||
_ *jwriter.Writer
|
||||
_ easyjson.Marshaler
|
||||
)
|
||||
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox(in *jlexer.Lexer, out *Properties) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "accuracy":
|
||||
out.Accuracy = string(in.String())
|
||||
case "short_code":
|
||||
out.ShortCode = string(in.String())
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox(out *jwriter.Writer, in Properties) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"accuracy\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.Accuracy))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"short_code\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.ShortCode))
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Properties) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Properties) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Properties) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Properties) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox(l, v)
|
||||
}
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox1(in *jlexer.Lexer, out *Geometry) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "type":
|
||||
out.Type = string(in.String())
|
||||
case "coordinates":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Coordinates = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Coordinates == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Coordinates = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.Coordinates = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.Coordinates = (out.Coordinates)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v1 float64
|
||||
v1 = float64(in.Float64())
|
||||
out.Coordinates = append(out.Coordinates, v1)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox1(out *jwriter.Writer, in Geometry) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"type\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.Type))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"coordinates\":"
|
||||
out.RawString(prefix)
|
||||
if in.Coordinates == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v2, v3 := range in.Coordinates {
|
||||
if v2 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v3))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Geometry) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox1(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Geometry) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox1(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Geometry) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox1(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Geometry) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox1(l, v)
|
||||
}
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox2(in *jlexer.Lexer, out *Feature) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "id":
|
||||
out.ID = string(in.String())
|
||||
case "type":
|
||||
out.Type = string(in.String())
|
||||
case "place_type":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.PlaceType = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.PlaceType == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.PlaceType = make([]string, 0, 4)
|
||||
} else {
|
||||
out.PlaceType = []string{}
|
||||
}
|
||||
} else {
|
||||
out.PlaceType = (out.PlaceType)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v4 string
|
||||
v4 = string(in.String())
|
||||
out.PlaceType = append(out.PlaceType, v4)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "relevance":
|
||||
out.Relevance = float64(in.Float64())
|
||||
case "properties":
|
||||
(out.Properties).UnmarshalEasyJSON(in)
|
||||
case "text":
|
||||
out.Text = string(in.String())
|
||||
case "place_name":
|
||||
out.PlaceName = string(in.String())
|
||||
case "center":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Center = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Center == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Center = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.Center = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.Center = (out.Center)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v5 float64
|
||||
v5 = float64(in.Float64())
|
||||
out.Center = append(out.Center, v5)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "geometry":
|
||||
(out.Geometry).UnmarshalEasyJSON(in)
|
||||
case "address":
|
||||
out.Address = string(in.String())
|
||||
case "context":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Context = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Context == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Context = make([]Context, 0, 1)
|
||||
} else {
|
||||
out.Context = []Context{}
|
||||
}
|
||||
} else {
|
||||
out.Context = (out.Context)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v6 Context
|
||||
(v6).UnmarshalEasyJSON(in)
|
||||
out.Context = append(out.Context, v6)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "bbox":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.BoundingBox = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.BoundingBox == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.BoundingBox = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.BoundingBox = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.BoundingBox = (out.BoundingBox)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v7 float64
|
||||
v7 = float64(in.Float64())
|
||||
out.BoundingBox = append(out.BoundingBox, v7)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox2(out *jwriter.Writer, in Feature) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"id\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.ID))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"type\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Type))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"place_type\":"
|
||||
out.RawString(prefix)
|
||||
if in.PlaceType == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v8, v9 := range in.PlaceType {
|
||||
if v8 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v9))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"relevance\":"
|
||||
out.RawString(prefix)
|
||||
out.Float64(float64(in.Relevance))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"properties\":"
|
||||
out.RawString(prefix)
|
||||
(in.Properties).MarshalEasyJSON(out)
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"text\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Text))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"place_name\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.PlaceName))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"center\":"
|
||||
out.RawString(prefix)
|
||||
if in.Center == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v10, v11 := range in.Center {
|
||||
if v10 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v11))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"geometry\":"
|
||||
out.RawString(prefix)
|
||||
(in.Geometry).MarshalEasyJSON(out)
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"address\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Address))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"context\":"
|
||||
out.RawString(prefix)
|
||||
if in.Context == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v12, v13 := range in.Context {
|
||||
if v12 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v13).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"bbox\":"
|
||||
out.RawString(prefix)
|
||||
if in.BoundingBox == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v14, v15 := range in.BoundingBox {
|
||||
if v14 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v15))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Feature) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox2(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Feature) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox2(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Feature) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox2(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Feature) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox2(l, v)
|
||||
}
|
||||
func easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox3(in *jlexer.Lexer, out *Context) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "id":
|
||||
out.ID = string(in.String())
|
||||
case "text":
|
||||
out.Text = string(in.String())
|
||||
case "wikidata":
|
||||
out.Wikidata = string(in.String())
|
||||
case "short_code":
|
||||
out.ShortCode = string(in.String())
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox3(out *jwriter.Writer, in Context) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"id\":"
|
||||
out.RawString(prefix[1:])
|
||||
out.String(string(in.ID))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"text\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Text))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"wikidata\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.Wikidata))
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"short_code\":"
|
||||
out.RawString(prefix)
|
||||
out.String(string(in.ShortCode))
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v Context) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox3(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v Context) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson3e8ab7adEncodeGithubComHumansNetMapboxSdkGoMapbox3(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *Context) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox3(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *Context) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson3e8ab7adDecodeGithubComHumansNetMapboxSdkGoMapbox3(l, v)
|
||||
}
|
||||
421
services/location/mapbox_lib/geocode.go
Normal file
421
services/location/mapbox_lib/geocode.go
Normal file
@@ -0,0 +1,421 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
const (
|
||||
limit = "limit"
|
||||
types = "types"
|
||||
country = "country"
|
||||
language = "language"
|
||||
reverseMode = "reverseMode"
|
||||
autocomplete = "autocomplete"
|
||||
fuzzymatch = "fuzzymatch"
|
||||
bbox = "bbox"
|
||||
proximity = "proximity"
|
||||
routing = "routing"
|
||||
trueStr = "true"
|
||||
oneStr = "1"
|
||||
|
||||
access_token = "access_token"
|
||||
|
||||
floatFormatNoExponent = 'f'
|
||||
|
||||
respHeaderRateLimitInterval = "X-Rate-Limit-Interval"
|
||||
respHeaderRateLimitLimit = "X-Rate-Limit-Limit"
|
||||
respHeaderRateLimitReset = "X-Rate-Limit-Reset"
|
||||
)
|
||||
|
||||
var (
|
||||
responseFormatJSON = []byte(".json")
|
||||
getMethod = []byte("GET")
|
||||
)
|
||||
|
||||
type GeoPoint struct {
|
||||
Lon float64
|
||||
Lat float64
|
||||
}
|
||||
|
||||
type ReverseGeocodeRequest struct {
|
||||
GeoPoint GeoPoint
|
||||
// Limit results to one or more countries.
|
||||
Limit int
|
||||
// Filter results to include only a subset (one or more) of the available feature types.
|
||||
// Options are country, region, postcode, district, place, locality, neighborhood, address, and poi.
|
||||
// Multiple options can be comma-separated. Note that poi.landmark is a deprecated type that, while still supported,
|
||||
// returns the same data as is returned using the poi type.
|
||||
Types []string
|
||||
// Permitted values are ISO 3166 alpha 2(https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country codes separated by commas.
|
||||
Country string
|
||||
// Specify the user’s language. This parameter controls the language of the text supplied in responses.
|
||||
// Options are IETF language tags comprised of a mandatory ISO 639-1 language code and, optionally,
|
||||
// one or more IETF subtags for country or script.
|
||||
// More than one value can also be specified, separated by commas,
|
||||
// for applications that need to display labels in multiple languages.
|
||||
// For more information on which specific languages are supported, see https://docs.mapbox.com/api/search/#language-coverage
|
||||
Language string
|
||||
// Decides how results are sorted in a reverse geocoding query
|
||||
// if multiple results are requested using a limit other than 1.
|
||||
// Options are distance (default), which causes the closest feature
|
||||
// to always be returned first, and score, which allows high-prominence features
|
||||
// to be sorted higher than nearer, lower-prominence features.
|
||||
ReverseMode int
|
||||
// Specify whether to request additional metadata about the recommended navigation destination corresponding
|
||||
// to the feature (true) or not (false, default). Only applicable for address features.
|
||||
// For example, if routing=true the response could include data about a point on the road the feature fronts.
|
||||
// Response features may include an array containing one or more routable points.
|
||||
// Routable points cannot always be determined.
|
||||
// Consuming applications should fall back to using the feature’s normal geometry for routing
|
||||
// if a separate routable point is not returned.
|
||||
Routing bool
|
||||
}
|
||||
|
||||
// RateLimit wraps mapbox API rate limit resp headers
|
||||
type RateLimit struct {
|
||||
Interval []byte
|
||||
Limit []byte
|
||||
Reset []byte
|
||||
}
|
||||
|
||||
// easyjson:json
|
||||
type rawReverseGeoResp struct {
|
||||
Features []Feature `json:"features"`
|
||||
Query []float64 `json:"query"`
|
||||
}
|
||||
|
||||
// easyjson:json
|
||||
type rawForwardGeoResp struct {
|
||||
Features []Feature `json:"features"`
|
||||
Query []string `json:"query"`
|
||||
}
|
||||
|
||||
// GeocodeResponse
|
||||
type GeocodeResponse struct {
|
||||
RateLimit RateLimit
|
||||
// Raw mapbox API response
|
||||
RawResp []byte
|
||||
// passed query to mapbox
|
||||
ReverseQuery GeoPoint
|
||||
ForwardQuery []string
|
||||
// response result type
|
||||
Type string
|
||||
// response data
|
||||
Features []Feature
|
||||
}
|
||||
|
||||
type ForwardGeocodeRequest struct {
|
||||
//The feature you’re trying to look up.
|
||||
//This could be an address, a point of interest name, a city name, etc.
|
||||
//When searching for points of interest, it can also be a category name (for example, “coffee shop”).
|
||||
//For information on categories, see the Point of interest category coverage section.
|
||||
//The search text should be expressed as a URL-encoded UTF-8 string,
|
||||
//and must not contain the semicolon character (either raw or URL-encoded).
|
||||
//Your search text, once decoded, must consist of at most 20 words and numbers separated by spacing and punctuation,
|
||||
//and at most 256 characters.
|
||||
//
|
||||
//The accuracy of coordinates returned by a forward geocoding request can be impacted
|
||||
//by how the addresses in the query are formatted. Learn more about address formatting
|
||||
//best practices in the https://docs.mapbox.com/help/troubleshooting/address-geocoding-format-guide.
|
||||
SearchText string
|
||||
|
||||
//Specify whether to return autocomplete results (true, default) or not (false).
|
||||
//When autocomplete is enabled, results will be included that start with the requested string,
|
||||
//rather than just responses that match it exactly.
|
||||
//For example, a query for India might return both India and Indiana with autocomplete enabled,
|
||||
//but only India if it’s disabled.
|
||||
//
|
||||
//When autocomplete is enabled, each user keystroke counts as one request to the Geocoding API.
|
||||
//For example, a search for "coff" would be reflected as four separate Geocoding API requests.
|
||||
//To reduce the total requests sent, you can configure your application
|
||||
//to only call the Geocoding API after a specific number of characters are typed.
|
||||
Autocomplete *bool // default true
|
||||
|
||||
//Limit results to only those contained within the supplied bounding box
|
||||
//Bounding boxes should be supplied as four numbers separated by commas,
|
||||
//in minLon,minLat,maxLon,maxLat order.
|
||||
//The bounding box cannot cross the 180th meridian.
|
||||
Bbox []float64
|
||||
|
||||
//Limit results to one or more countries.
|
||||
//Permitted values are ISO 3166 alpha 2 country codes separated by commas.
|
||||
Country string
|
||||
|
||||
//Specify whether the Geocoding API should attempt approximate,
|
||||
//as well as exact, matching when performing searches (true, default),
|
||||
//or whether it should opt out of this behavior and only attempt exact matching (false).
|
||||
//For example, the default setting might return Washington, DC for a query of wahsington,
|
||||
//even though the query was misspelled.
|
||||
FuzzyMatch *bool // default true
|
||||
|
||||
//Specify the user’s language.
|
||||
//This parameter controls the language of the text supplied in responses, and also affects result scoring,
|
||||
//with results matching the user’s query in the requested language being preferred over results
|
||||
//that match in another language. For example, an autocomplete query for things
|
||||
//that start with Frank might return Frankfurt as the first result with an English (en) language parameter,
|
||||
//but Frankreich (“France”) with a German (de) language parameter.
|
||||
//
|
||||
//Options are IETF language tags comprised of a mandatory ISO 639-1 language code and, optionally,
|
||||
//one or more IETF subtags for country or script.
|
||||
//
|
||||
//More than one value can also be specified, separated by commas,
|
||||
//for applications that need to display labels in multiple languages.
|
||||
//
|
||||
//For more information on which specific languages are supported, see the https://docs.mapbox.com/api/search/#language-coverage.
|
||||
Language string
|
||||
|
||||
//Specify the maximum number of results to return. The default is 5 and the maximum supported is 10.
|
||||
Limit int // default 5
|
||||
|
||||
//Bias the response to favor results that are closer to this location
|
||||
Proximity *GeoPoint
|
||||
|
||||
//Specify whether to request additional metadata about the recommended navigation destination
|
||||
//corresponding to the feature (true) or not (false, default). Only applicable for address features.
|
||||
//
|
||||
//For example, if routing=true the response could include data about a point on the road the feature fronts.
|
||||
//Response features may include an array containing one or more routable points.
|
||||
//Routable points cannot always be determined.
|
||||
//Consuming applications should fall back to using the feature’s normal geometry for routing
|
||||
//if a separate routable point is not returned.
|
||||
Routing bool //default false
|
||||
|
||||
//Filter results to include only a subset (one or more) of the available feature types.
|
||||
//Options are country, region, postcode, district, place, locality, neighborhood, address, and poi.
|
||||
//Multiple options can be comma-separated. Note that poi.landmark is a deprecated type that,
|
||||
//while still supported, returns the same data as is returned using the poi type.
|
||||
//
|
||||
//For more information on the available types, see the https://docs.mapbox.com/api/search/#data-types.
|
||||
Types []string
|
||||
}
|
||||
|
||||
// Geocoder encapsulates forward and reverse geocode calls.
|
||||
type Geocoder interface {
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API
|
||||
ReverseGeocode(ctx context.Context, req *ReverseGeocodeRequest) (*GeocodeResponse, error)
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API
|
||||
ForwardGeocode(ctx context.Context, req *ForwardGeocodeRequest) (*GeocodeResponse, error)
|
||||
}
|
||||
|
||||
// FastHttpGeocoder is a fasthttp Geocoder implementation
|
||||
type FastHttpGeocoder struct {
|
||||
config
|
||||
|
||||
geocodeAPIURL []byte
|
||||
|
||||
stringBufPull *stringsBufferPool
|
||||
}
|
||||
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API thought fasthttp client.
|
||||
func (c *FastHttpGeocoder) ReverseGeocode(ctx context.Context, req *ReverseGeocodeRequest) (*GeocodeResponse, error) {
|
||||
freq := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(freq)
|
||||
|
||||
fresp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(fresp)
|
||||
|
||||
// split multivalues to limit memory consumption
|
||||
values := make(map[string]string, 5)
|
||||
|
||||
if req.Country != "" {
|
||||
values[country] = req.Country
|
||||
}
|
||||
if req.Limit != 0 {
|
||||
values[limit] = strconv.Itoa(req.Limit)
|
||||
}
|
||||
if req.Language != "" {
|
||||
values[language] = req.Language
|
||||
}
|
||||
if req.Routing {
|
||||
values[routing] = trueStr
|
||||
}
|
||||
if req.ReverseMode == 1 {
|
||||
values[reverseMode] = oneStr
|
||||
}
|
||||
if len(req.Types) > 0 {
|
||||
values[types] = strings.Join(req.Types, ",")
|
||||
}
|
||||
|
||||
buf := c.stringBufPull.acquireStringsBuilder()
|
||||
defer c.stringBufPull.releaseStringsBuilder(buf)
|
||||
|
||||
buf.Write(c.geocodeAPIURL)
|
||||
buf.WriteString(strconv.FormatFloat(req.GeoPoint.Lon, floatFormatNoExponent, 6, 64))
|
||||
buf.WriteByte(comma)
|
||||
buf.WriteString(strconv.FormatFloat(req.GeoPoint.Lat, floatFormatNoExponent, 6, 64))
|
||||
buf.Write(responseFormatJSON)
|
||||
buf.Write(c.accessTokenGetValue)
|
||||
|
||||
encodeValues(buf, values)
|
||||
|
||||
reqURI := buf.Bytes()
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: reverse geocode request %s", buf.String())
|
||||
})
|
||||
|
||||
freq.Header.SetMethodBytes(getMethod)
|
||||
freq.SetRequestURIBytes(reqURI)
|
||||
|
||||
if err := c.client.Do(freq, fresp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respBytes := make([]byte, len(fresp.Body()))
|
||||
copy(respBytes, fresp.Body())
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: reverse geocode response %s", string(respBytes))
|
||||
})
|
||||
|
||||
if fresp.Header.StatusCode() != http.StatusOK {
|
||||
return nil, errors.Errorf("failed to reverse geocode URI %s statusCode %d resp %s",
|
||||
reqURI, fresp.Header.StatusCode(), string(respBytes))
|
||||
}
|
||||
|
||||
respRaw := rawReverseGeoResp{}
|
||||
if err := respRaw.UnmarshalJSON(respBytes); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshall raw reverse geocode resp %s", string(respBytes))
|
||||
}
|
||||
|
||||
if len(respRaw.Query) != 2 {
|
||||
return nil, errors.Errorf("unexpected len of query coordinates in resp %s", string(respBytes))
|
||||
}
|
||||
|
||||
return &GeocodeResponse{
|
||||
RateLimit: readRespRateLimit(fresp),
|
||||
RawResp: respBytes,
|
||||
ReverseQuery: GeoPoint{
|
||||
Lon: respRaw.Query[0],
|
||||
Lat: respRaw.Query[1],
|
||||
},
|
||||
Features: respRaw.Features,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReverseGeocode calls geocode/v5 reverse mapbox API thought fasthttp client.
|
||||
func (c *FastHttpGeocoder) ForwardGeocode(ctx context.Context, req *ForwardGeocodeRequest) (*GeocodeResponse, error) {
|
||||
freq := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(freq)
|
||||
|
||||
fresp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(fresp)
|
||||
|
||||
// split multivalues to limit memory consumption
|
||||
values := make(map[string]string, 9)
|
||||
|
||||
if req.Country != "" {
|
||||
values[country] = req.Country
|
||||
}
|
||||
if req.Limit != 0 {
|
||||
values[limit] = strconv.Itoa(req.Limit)
|
||||
}
|
||||
if req.Language != "" {
|
||||
values[language] = req.Language
|
||||
}
|
||||
if req.Routing {
|
||||
values[routing] = trueStr
|
||||
}
|
||||
if req.Autocomplete != nil {
|
||||
values[autocomplete] = fmt.Sprint(*req.Autocomplete)
|
||||
} else {
|
||||
values[autocomplete] = trueStr
|
||||
}
|
||||
if req.FuzzyMatch != nil {
|
||||
values[fuzzymatch] = fmt.Sprint(*req.FuzzyMatch)
|
||||
} else {
|
||||
values[fuzzymatch] = trueStr
|
||||
}
|
||||
if len(req.Bbox) == 4 {
|
||||
values[bbox] = fmt.Sprintf("%f,%f,%f,%f", req.Bbox[0], req.Bbox[1], req.Bbox[2], req.Bbox[3])
|
||||
}
|
||||
if req.Proximity != nil {
|
||||
values[proximity] = fmt.Sprintf("%f,%f", req.Proximity.Lon, req.Proximity.Lat)
|
||||
}
|
||||
values[routing] = fmt.Sprint(req.Routing)
|
||||
if len(req.Types) > 0 {
|
||||
values[types] = strings.Join(req.Types, ",")
|
||||
}
|
||||
|
||||
buf := c.stringBufPull.acquireStringsBuilder()
|
||||
defer c.stringBufPull.releaseStringsBuilder(buf)
|
||||
|
||||
buf.Write(c.geocodeAPIURL)
|
||||
buf.WriteString(req.SearchText)
|
||||
buf.Write(responseFormatJSON)
|
||||
buf.Write(c.accessTokenGetValue)
|
||||
|
||||
encodeValues(buf, values)
|
||||
|
||||
reqURI := buf.Bytes()
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: forward geocode request %s", buf.String())
|
||||
})
|
||||
|
||||
freq.Header.SetMethodBytes(getMethod)
|
||||
freq.SetRequestURIBytes(reqURI)
|
||||
|
||||
if err := c.client.Do(freq, fresp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respBytes := make([]byte, len(fresp.Body()))
|
||||
copy(respBytes, fresp.Body())
|
||||
|
||||
c.withLogger(ctx, func(logger Logger) {
|
||||
logger.Debugf("mapbox_sdk: forward geocode response %s", string(respBytes))
|
||||
})
|
||||
|
||||
if fresp.Header.StatusCode() != http.StatusOK {
|
||||
return nil, errors.Errorf("failed to reverse geocode URI %s statusCode %d resp %s",
|
||||
reqURI, fresp.Header.StatusCode(), string(respBytes))
|
||||
}
|
||||
|
||||
respRaw := rawForwardGeoResp{}
|
||||
if err := respRaw.UnmarshalJSON(respBytes); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshall raw reverse geocode resp %s", string(respBytes))
|
||||
}
|
||||
|
||||
return &GeocodeResponse{
|
||||
RateLimit: readRespRateLimit(fresp),
|
||||
RawResp: respBytes,
|
||||
Features: respRaw.Features,
|
||||
ForwardQuery: respRaw.Query,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewFastHttpGeocoder(opts ...Option) *FastHttpGeocoder {
|
||||
c := FastHttpGeocoder{
|
||||
config: newConfig(),
|
||||
stringBufPull: newStringsBufferPool(),
|
||||
geocodeAPIURL: []byte("/geocoding/v5/"),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
c.config = o(c.config)
|
||||
}
|
||||
|
||||
c.config = c.config.withEnv()
|
||||
c.config = c.config.prepare()
|
||||
|
||||
c.geocodeAPIURL = []byte(c.rootAPI + string(c.geocodeAPIURL) + c.geocodeEndpoint + slash)
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func readRespRateLimit(resp *fasthttp.Response) RateLimit {
|
||||
return RateLimit{
|
||||
Interval: resp.Header.Peek(respHeaderRateLimitInterval),
|
||||
Limit: resp.Header.Peek(respHeaderRateLimitLimit),
|
||||
Reset: resp.Header.Peek(respHeaderRateLimitReset),
|
||||
}
|
||||
}
|
||||
293
services/location/mapbox_lib/geocode_easyjson.go
Normal file
293
services/location/mapbox_lib/geocode_easyjson.go
Normal file
@@ -0,0 +1,293 @@
|
||||
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
|
||||
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
easyjson "github.com/mailru/easyjson"
|
||||
jlexer "github.com/mailru/easyjson/jlexer"
|
||||
jwriter "github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
// suppress unused package warning
|
||||
var (
|
||||
_ *json.RawMessage
|
||||
_ *jlexer.Lexer
|
||||
_ *jwriter.Writer
|
||||
_ easyjson.Marshaler
|
||||
)
|
||||
|
||||
func easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox(in *jlexer.Lexer, out *rawReverseGeoResp) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "features":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Features = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Features == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Features = make([]Feature, 0, 1)
|
||||
} else {
|
||||
out.Features = []Feature{}
|
||||
}
|
||||
} else {
|
||||
out.Features = (out.Features)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v1 Feature
|
||||
(v1).UnmarshalEasyJSON(in)
|
||||
out.Features = append(out.Features, v1)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "query":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Query = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Query == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Query = make([]float64, 0, 8)
|
||||
} else {
|
||||
out.Query = []float64{}
|
||||
}
|
||||
} else {
|
||||
out.Query = (out.Query)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v2 float64
|
||||
v2 = float64(in.Float64())
|
||||
out.Query = append(out.Query, v2)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox(out *jwriter.Writer, in rawReverseGeoResp) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"features\":"
|
||||
out.RawString(prefix[1:])
|
||||
if in.Features == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v3, v4 := range in.Features {
|
||||
if v3 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v4).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"query\":"
|
||||
out.RawString(prefix)
|
||||
if in.Query == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v5, v6 := range in.Query {
|
||||
if v5 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Float64(float64(v6))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v rawReverseGeoResp) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v rawReverseGeoResp) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *rawReverseGeoResp) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *rawReverseGeoResp) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox(l, v)
|
||||
}
|
||||
func easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox1(in *jlexer.Lexer, out *rawForwardGeoResp) {
|
||||
isTopLevel := in.IsStart()
|
||||
if in.IsNull() {
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "features":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Features = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Features == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Features = make([]Feature, 0, 1)
|
||||
} else {
|
||||
out.Features = []Feature{}
|
||||
}
|
||||
} else {
|
||||
out.Features = (out.Features)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v7 Feature
|
||||
(v7).UnmarshalEasyJSON(in)
|
||||
out.Features = append(out.Features, v7)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
case "query":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Query = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Query == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Query = make([]string, 0, 4)
|
||||
} else {
|
||||
out.Query = []string{}
|
||||
}
|
||||
} else {
|
||||
out.Query = (out.Query)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v8 string
|
||||
v8 = string(in.String())
|
||||
out.Query = append(out.Query, v8)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
if isTopLevel {
|
||||
in.Consumed()
|
||||
}
|
||||
}
|
||||
func easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox1(out *jwriter.Writer, in rawForwardGeoResp) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
{
|
||||
const prefix string = ",\"features\":"
|
||||
out.RawString(prefix[1:])
|
||||
if in.Features == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v9, v10 := range in.Features {
|
||||
if v9 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v10).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
{
|
||||
const prefix string = ",\"query\":"
|
||||
out.RawString(prefix)
|
||||
if in.Query == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
|
||||
out.RawString("null")
|
||||
} else {
|
||||
out.RawByte('[')
|
||||
for v11, v12 := range in.Query {
|
||||
if v11 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v12))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
// MarshalJSON supports json.Marshaler interface
|
||||
func (v rawForwardGeoResp) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox1(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
|
||||
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||
func (v rawForwardGeoResp) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson46e924aeEncodeGithubComHumansNetMapboxSdkGoMapbox1(w, v)
|
||||
}
|
||||
|
||||
// UnmarshalJSON supports json.Unmarshaler interface
|
||||
func (v *rawForwardGeoResp) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox1(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||
func (v *rawForwardGeoResp) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson46e924aeDecodeGithubComHumansNetMapboxSdkGoMapbox1(l, v)
|
||||
}
|
||||
9
services/location/mapbox_lib/http.go
Normal file
9
services/location/mapbox_lib/http.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
type FastHttpClient interface {
|
||||
Do(req *fasthttp.Request, resp *fasthttp.Response) error
|
||||
}
|
||||
22
services/location/mapbox_lib/logger.go
Normal file
22
services/location/mapbox_lib/logger.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Logger interface {
|
||||
Debugf(msg string, params ...interface{})
|
||||
Errorf(msg string, params ...interface{})
|
||||
}
|
||||
|
||||
// withLogger helps to reduce unnecessary allocations
|
||||
func (c *config) withLogger(ctx context.Context, do func(Logger)) {
|
||||
if c.requestLogger != nil {
|
||||
do(c.requestLogger(ctx))
|
||||
return
|
||||
}
|
||||
|
||||
if c.logger != nil {
|
||||
do(c.logger)
|
||||
}
|
||||
}
|
||||
31
services/location/mapbox_lib/pools.go
Normal file
31
services/location/mapbox_lib/pools.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type noCopy struct{}
|
||||
|
||||
func (*noCopy) Lock() {}
|
||||
func (*noCopy) Unlock() {}
|
||||
|
||||
type stringsBufferPool struct {
|
||||
noCopy noCopy
|
||||
p sync.Pool
|
||||
}
|
||||
|
||||
func newStringsBufferPool() *stringsBufferPool {
|
||||
return &stringsBufferPool{p: sync.Pool{New: func() interface{} {
|
||||
return &bytes.Buffer{}
|
||||
}}}
|
||||
}
|
||||
|
||||
func (pool *stringsBufferPool) acquireStringsBuilder() *bytes.Buffer {
|
||||
return pool.p.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func (pool *stringsBufferPool) releaseStringsBuilder(b *bytes.Buffer) {
|
||||
b.Reset()
|
||||
pool.p.Put(b)
|
||||
}
|
||||
23
services/location/mapbox_lib/values.go
Normal file
23
services/location/mapbox_lib/values.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package mapbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
const (
|
||||
slash = "/"
|
||||
comma = ','
|
||||
questionMark = "?"
|
||||
equalMark = '='
|
||||
ampersandMark = '&'
|
||||
)
|
||||
|
||||
// encodeValues do almost the same as url.Values.Encode() but faster and reuses *strings.Builder
|
||||
func encodeValues(buf *bytes.Buffer, values map[string]string) {
|
||||
for k, v := range values {
|
||||
buf.WriteByte(ampersandMark)
|
||||
buf.WriteString(k)
|
||||
buf.WriteByte(equalMark)
|
||||
buf.WriteString(v)
|
||||
}
|
||||
}
|
||||
99
services/messaging/messaging_service.go
Normal file
99
services/messaging/messaging_service.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package messaging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ses"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
ch chan models.Notification
|
||||
db *gorm.DB
|
||||
ech chan models.EmailNotification
|
||||
ses *ses.SES
|
||||
}
|
||||
|
||||
var MessagingChannel chan models.Notification
|
||||
var EmailChannel chan models.EmailNotification
|
||||
|
||||
func NewService(ch chan models.Notification, ech chan models.EmailNotification, db *gorm.DB) service {
|
||||
MessagingChannel = ch
|
||||
EmailChannel = ech
|
||||
log.Printf("Aws %v , %v", config.AppConfig.AWS.AccessKey, config.AppConfig.AWS.SecretKey)
|
||||
// Create a new session in the us-west-2 region.
|
||||
sess, err := session.NewSession(&aws.Config{
|
||||
Region: aws.String("us-east-1"),
|
||||
Credentials: credentials.NewStaticCredentials(config.AppConfig.AWS.AccessKey, config.AppConfig.AWS.SecretKey, "")},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating AWS session: %v\n", err)
|
||||
return service{}
|
||||
}
|
||||
// Create an SES session.
|
||||
svc := ses.New(sess)
|
||||
return service{
|
||||
ch: MessagingChannel,
|
||||
ech: EmailChannel,
|
||||
ses: svc,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s service) MessagingService() {
|
||||
for notification := range s.ch {
|
||||
fmt.Println("Messaging Service received: ", notification)
|
||||
|
||||
// Save the notification to the database
|
||||
if err := s.db.Create(¬ification).Error; err != nil {
|
||||
fmt.Printf("Error saving notification to DB: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s service) SendEmailService() {
|
||||
for emailNotification := range s.ech {
|
||||
fmt.Println("Email Service received: ", emailNotification)
|
||||
|
||||
// Send email via SES
|
||||
input := &ses.SendEmailInput{
|
||||
Destination: &ses.Destination{
|
||||
ToAddresses: []*string{
|
||||
aws.String(emailNotification.Email),
|
||||
},
|
||||
},
|
||||
Message: &ses.Message{
|
||||
Body: &ses.Body{
|
||||
Text: &ses.Content{
|
||||
Data: aws.String(emailNotification.Body),
|
||||
},
|
||||
},
|
||||
Subject: &ses.Content{
|
||||
Data: aws.String(emailNotification.Subject),
|
||||
},
|
||||
},
|
||||
Source: aws.String("app@pactualdev.com"), // Replace with your SES verified email address
|
||||
}
|
||||
_, err := s.ses.SendEmail(input)
|
||||
if err != nil {
|
||||
fmt.Printf("Error sending email: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("Email sent successfully")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetMessagingChannel() chan models.Notification {
|
||||
return MessagingChannel
|
||||
}
|
||||
|
||||
func GetEmailChannel() chan models.EmailNotification {
|
||||
return EmailChannel
|
||||
}
|
||||
@@ -3,43 +3,46 @@ package shared
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"novatech/config"
|
||||
"novatech/models"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||
"gitlab.com/pactual1/backend/config"
|
||||
"gitlab.com/pactual1/backend/models"
|
||||
)
|
||||
|
||||
|
||||
var db *gorm.DB
|
||||
var err error
|
||||
|
||||
|
||||
func Init() error{
|
||||
host := config.AppConfig.Database.HostName
|
||||
user := config.AppConfig.Database.UserName
|
||||
func Init() error {
|
||||
host := config.AppConfig.Database.HostName
|
||||
user := config.AppConfig.Database.UserName
|
||||
// port := config.AppConfig.Database.Port
|
||||
dbName := config.AppConfig.Database.DatabaseName
|
||||
password := config.AppConfig.Database.Password
|
||||
dbName := config.AppConfig.Database.DatabaseName
|
||||
password := config.AppConfig.Database.Password
|
||||
|
||||
dbString:= fmt.Sprintf("host=%s user=%s dbname=%s sslmode=disable password=%s",host,user,dbName,password)
|
||||
dbString := fmt.Sprintf("host=%s user=%s dbname=%s sslmode=disable password=%s", host, user, dbName, password)
|
||||
// db, err = gorm.Open("postgres", "host=localhost user=postgres dbname=postgres sslmode=disable password=root")
|
||||
var err error
|
||||
|
||||
// //PostgreSQL
|
||||
db, err = gorm.Open("postgres",dbString)
|
||||
db, err = gorm.Open("postgres", dbString)
|
||||
|
||||
db.LogMode(true)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error initializing the database: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
//TODO AUTOMIGRATE models once we have them
|
||||
db.AutoMigrate(&models.User{}, &models.Company{}, &models.Device{})
|
||||
db.AutoMigrate(&models.User{}, &models.Company{}, &models.Device{}, &models.DeviceInfo{},
|
||||
&models.Contract{}, &models.ContractInfo{},
|
||||
&models.ProductTemplate{}, &models.TextTemplate{}, &models.Invoice{}, &models.InvoiceItem{},
|
||||
&models.Notification{}, models.PasswordTokens{}, models.SessionToken{})
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
|
||||
func GetDb() *gorm.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
104
shared/encryption.go
Normal file
104
shared/encryption.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func GenerateRandomString(length int) string {
|
||||
b := make([]byte, length)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
func CovertUintToByte32(id uint) [32]byte {
|
||||
b := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint32(b, uint32(id))
|
||||
return [32]byte(b)
|
||||
}
|
||||
|
||||
type EncryptionClient interface {
|
||||
Encrypt(string) (string, error)
|
||||
Decrypt(string) (string, error)
|
||||
}
|
||||
|
||||
type encryptionClient struct {
|
||||
Secret string
|
||||
}
|
||||
|
||||
func NewEncryptionClient(secret string) EncryptionClient {
|
||||
return &encryptionClient{Secret: secret}
|
||||
}
|
||||
|
||||
func compress(text string) ([]byte, error) {
|
||||
var compressedBytes bytes.Buffer
|
||||
w, err := flate.NewWriter(&compressedBytes, flate.BestCompression)
|
||||
w.Write([]byte(text))
|
||||
w.Close()
|
||||
return compressedBytes.Bytes(), err
|
||||
}
|
||||
|
||||
func decompress(compressedBytes []byte) (string, error) {
|
||||
reader := flate.NewReader(bytes.NewReader(compressedBytes))
|
||||
defer reader.Close()
|
||||
textBytes := new(bytes.Buffer)
|
||||
_, err := textBytes.ReadFrom(reader)
|
||||
return textBytes.String(), err
|
||||
}
|
||||
|
||||
// Encrypt method is to encrypt or hide any classified text
|
||||
func (e encryptionClient) Encrypt(text string) (string, error) {
|
||||
block, err := aes.NewCipher([]byte(e.Secret))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
compressedText, err := compress(text)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bytes := make([]byte, gcm.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, bytes); err != nil {
|
||||
return "", err
|
||||
}
|
||||
encodedText := gcm.Seal(bytes, bytes, compressedText, nil)
|
||||
return base64.StdEncoding.EncodeToString(encodedText), nil
|
||||
}
|
||||
|
||||
// Decrypt method is to extract back the encrypted text
|
||||
func (e encryptionClient) Decrypt(text string) (string, error) {
|
||||
block, err := aes.NewCipher([]byte(e.Secret))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cipherText, err := base64.StdEncoding.DecodeString(text)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(cipherText) < gcm.NonceSize() {
|
||||
return "", fmt.Errorf("text is too small")
|
||||
}
|
||||
bytes, cipherText := cipherText[:gcm.NonceSize()], cipherText[gcm.NonceSize():]
|
||||
compressedTextBytes, err := gcm.Open(nil, bytes, cipherText, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return decompress(compressedTextBytes)
|
||||
}
|
||||
22
shared/encryption_test.go
Normal file
22
shared/encryption_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncryptionClient(t *testing.T) {
|
||||
|
||||
client := encryptionClient{Secret: `abc&1*~#^2^#s0^=)^^7%b34`}
|
||||
|
||||
t.Run("encrypt/ decyrpt works", func(t *testing.T) {
|
||||
text := "sample text to test encryption"
|
||||
encodedText, err := client.Encrypt(text)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, text, encodedText)
|
||||
decodedText, err := client.Decrypt(encodedText)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, text, decodedText)
|
||||
})
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Created by VoidArtanis on 11/2/2017
|
||||
*/
|
||||
|
||||
package shared
|
||||
|
||||
const (
|
||||
RoleAdmin string = "admin"
|
||||
RoleProUser string = "pro-user"
|
||||
)
|
||||
31
shared/user_data.go
Normal file
31
shared/user_data.go
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Created by VoidArtanis on 11/2/2017
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user