diff --git a/service/account/Makefile b/service/account/Makefile index 2474e962569..0d6b590f17b 100644 --- a/service/account/Makefile +++ b/service/account/Makefile @@ -42,7 +42,7 @@ clean: rm -f $(SERVICE_NAME) .PHONY: build -build: clean ## Build service-hub binary. +build: ## Build service-hub binary. CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) go build $(GO_BUILD_FLAGS) -o bin/manager main.go .PHONY: docker-build diff --git a/service/account/api/api.go b/service/account/api/api.go index 0a5d6c622e1..f2086403627 100644 --- a/service/account/api/api.go +++ b/service/account/api/api.go @@ -80,6 +80,99 @@ func GetProperties(c *gin.Context) { }) } +// GetConsumptionAmount +// @Summary Get user consumption amount +// @Description Get user consumption amount within a specified time range +// @Tags ConsumptionAmount +// @Accept json +// @Produce json +// @Param request body helper.UserCostsAmountReq true "User consumption amount request" +// @Success 200 {object} map[string]interface{} "successfully retrieved user consumption amount" +// @Failure 400 {object} map[string]interface{} "failed to parse user consumption amount request" +// @Failure 401 {object} map[string]interface{} "authenticate error" +// @Failure 500 {object} map[string]interface{} "failed to get user consumption amount" +// @Router /account/v1alpha1/costs/consumption [post] +func GetConsumptionAmount(c *gin.Context) { + req, err := helper.ParseUserCostsAmountReq(c) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("failed to parse user consumption amount request: %v", err)}) + return + } + if err := helper.Authenticate(req.Auth); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": fmt.Sprintf("authenticate error : %v", err)}) + return + } + amount, err := dao.DBClient.GetConsumptionAmount(req.Owner, req.TimeRange.StartTime, req.TimeRange.EndTime) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to get consumption amount : %v", err)}) + } + c.JSON(http.StatusOK, gin.H{ + "amount": amount, + }) +} + +// GetRechargeAmount +// @Summary Get user recharge amount +// @Description Get user recharge amount within a specified time range +// @Tags RechargeAmount +// @Accept json +// @Produce json +// @Param request body helper.UserCostsAmountReq true "User recharge amount request" +// @Success 200 {object} map[string]interface{} "successfully retrieved user recharge amount" +// @Failure 400 {object} map[string]interface{} "failed to parse user recharge amount request" +// @Failure 401 {object} map[string]interface{} "authenticate error" +// @Failure 500 {object} map[string]interface{} "failed to get user recharge amount" +// @Router /account/v1alpha1/costs/recharge [post] +func GetRechargeAmount(c *gin.Context) { + req, err := helper.ParseUserCostsAmountReq(c) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("failed to parse user recharge amount request: %v", err)}) + return + } + if err := helper.Authenticate(req.Auth); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": fmt.Sprintf("authenticate error : %v", err)}) + return + } + amount, err := dao.DBClient.GetRechargeAmount(req.Owner, req.TimeRange.StartTime, req.TimeRange.EndTime) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to get recharge amount : %v", err)}) + } + c.JSON(http.StatusOK, gin.H{ + "amount": amount, + }) +} + +// GetPropertiesUsedAmount +// @Summary Get user properties used amount +// @Description Get user properties used amount within a specified time range +// @Tags PropertiesUsedAmount +// @Accept json +// @Produce json +// @Param request body helper.UserCostsAmountReq true "User properties used amount request" +// @Success 200 {object} map[string]interface{} "successfully retrieved user properties used amount" +// @Failure 400 {object} map[string]interface{} "failed to parse user properties used amount request" +// @Failure 401 {object} map[string]interface{} "authenticate error" +// @Failure 500 {object} map[string]interface{} "failed to get user properties used amount" +// @Router /account/v1alpha1/costs/properties [post] +func GetPropertiesUsedAmount(c *gin.Context) { + req, err := helper.ParseUserCostsAmountReq(c) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("failed to parse user properties used amount request: %v", err)}) + return + } + if err := helper.Authenticate(req.Auth); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": fmt.Sprintf("authenticate error : %v", err)}) + return + } + amount, err := dao.DBClient.GetPropertiesUsedAmount(req.Owner, req.TimeRange.StartTime, req.TimeRange.EndTime) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to get properties used amount : %v", err)}) + } + c.JSON(http.StatusOK, gin.H{ + "amount": amount, + }) +} + type CostsResult struct { Data CostsResultData `json:"data" bson:"data"` Message string `json:"message" bson:"message"` @@ -110,7 +203,7 @@ func GetCosts(c *gin.Context) { c.JSON(http.StatusUnauthorized, gin.H{"error": fmt.Sprintf("authenticate error : %v", err)}) return } - costs, err := dao.DBClient.GetCostAmount(req.Auth.Owner, req.TimeRange.StartTime, req.TimeRange.EndTime) + costs, err := dao.DBClient.GetCosts(req.Auth.Owner, req.TimeRange.StartTime, req.TimeRange.EndTime) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to get cost : %v", err)}) } diff --git a/service/account/dao/init.go b/service/account/dao/init.go index 0597a5053b1..7ff57b99433 100644 --- a/service/account/dao/init.go +++ b/service/account/dao/init.go @@ -11,5 +11,9 @@ var DBClient Interface func InitDB() error { var err error DBClient, err = NewMongoInterface(os.Getenv(helper.EnvMongoURI)) + if err != nil { + return err + } + _, err = DBClient.GetProperties() return err } diff --git a/service/account/dao/interface.go b/service/account/dao/interface.go index 2c27e29140f..88dd1be0833 100644 --- a/service/account/dao/interface.go +++ b/service/account/dao/interface.go @@ -20,7 +20,10 @@ import ( type Interface interface { GetBillingHistoryNamespaceList(req *helper.NamespaceBillingHistoryReq) ([]string, error) GetProperties() ([]common.PropertyQuery, error) - GetCostAmount(user string, startTime, endTime time.Time) (common.TimeCostsMap, error) + GetCosts(user string, startTime, endTime time.Time) (common.TimeCostsMap, error) + GetConsumptionAmount(user string, startTime, endTime time.Time) (int64, error) + GetRechargeAmount(user string, startTime, endTime time.Time) (int64, error) + GetPropertiesUsedAmount(user string, startTime, endTime time.Time) (map[string]int64, error) } type MongoDB struct { @@ -41,9 +44,13 @@ func (m *MongoDB) GetProperties() ([]common.PropertyQuery, error) { m.Properties = properties } for _, types := range m.Properties.Types { + price := types.ViewPrice + if price == 0 { + price = types.UnitPrice + } property := common.PropertyQuery{ Name: types.Name, - UnitPrice: types.ViewPrice, + UnitPrice: price, Unit: types.UnitString, Alias: types.Alias, } @@ -52,7 +59,7 @@ func (m *MongoDB) GetProperties() ([]common.PropertyQuery, error) { return propertiesQuery, nil } -func (m *MongoDB) GetCostAmount(user string, startTime, endTime time.Time) (common.TimeCostsMap, error) { +func (m *MongoDB) GetCosts(user string, startTime, endTime time.Time) (common.TimeCostsMap, error) { filter := bson.M{ "type": 0, "time": bson.M{ @@ -84,6 +91,87 @@ func (m *MongoDB) GetCostAmount(user string, startTime, endTime time.Time) (comm return costsMap, nil } +func (m *MongoDB) GetConsumptionAmount(user string, startTime, endTime time.Time) (int64, error) { + return m.getAmountWithType(0, user, startTime, endTime) +} + +func (m *MongoDB) GetRechargeAmount(user string, startTime, endTime time.Time) (int64, error) { + return m.getAmountWithType(1, user, startTime, endTime) +} + +func (m *MongoDB) getAmountWithType(_type int64, user string, startTime, endTime time.Time) (int64, error) { + pipeline := bson.A{ + bson.D{{Key: "$match", Value: bson.M{ + "type": _type, + "time": bson.M{"$gte": startTime, "$lte": endTime}, + "owner": user, + }}}, + bson.D{{Key: "$group", Value: bson.M{ + "_id": nil, + "total": bson.M{"$sum": "$amount"}, + }}}, + } + + cursor, err := m.getBillingCollection().Aggregate(context.Background(), pipeline) + if err != nil { + return 0, fmt.Errorf("failed to aggregate billing collection: %v", err) + } + defer cursor.Close(context.Background()) + + var result struct { + Total int64 `bson:"total"` + } + + if cursor.Next(context.Background()) { + if err := cursor.Decode(&result); err != nil { + return 0, fmt.Errorf("failed to decode result: %v", err) + } + } + return result.Total, nil +} + +func (m *MongoDB) GetPropertiesUsedAmount(user string, startTime, endTime time.Time) (map[string]int64, error) { + propertiesUsedAmount := make(map[string]int64) + for _, property := range m.Properties.Types { + amount, err := m.getSumOfUsedAmount(property.Enum, user, startTime, endTime) + if err != nil { + return nil, fmt.Errorf("failed to get sum of used amount: %v", err) + } + propertiesUsedAmount[property.Name] = amount + } + return propertiesUsedAmount, nil +} + +func (m *MongoDB) getSumOfUsedAmount(propertyType uint8, user string, startTime, endTime time.Time) (int64, error) { + pipeline := bson.A{ + bson.D{{Key: "$match", Value: bson.M{ + "time": bson.M{"$gte": startTime, "$lte": endTime}, + "owner": user, + "app_costs.used_amount.0": bson.M{"$exists": true}, + }}}, + bson.D{{Key: "$unwind", Value: "$app_costs"}}, + bson.D{{Key: "$group", Value: bson.M{ + "_id": nil, + "totalAmount": bson.M{"$sum": "$app_costs.used_amount." + strconv.Itoa(int(propertyType))}, + }}}, + } + cursor, err := m.getBillingCollection().Aggregate(context.Background(), pipeline) + if err != nil { + return 0, fmt.Errorf("failed to get billing collection: %v", err) + } + defer cursor.Close(context.Background()) + var result struct { + TotalAmount int64 `bson:"totalAmount"` + } + + if cursor.Next(context.Background()) { + if err := cursor.Decode(&result); err != nil { + return 0, fmt.Errorf("failed to decode result: %v", err) + } + } + return result.TotalAmount, nil +} + func NewMongoInterface(url string) (Interface, error) { client, err := mongo.Connect(context.Background(), options.Client().ApplyURI(url)) if err != nil { diff --git a/service/account/dao/interface_test.go b/service/account/dao/interface_test.go new file mode 100644 index 00000000000..bf7e09c398d --- /dev/null +++ b/service/account/dao/interface_test.go @@ -0,0 +1,52 @@ +package dao + +import ( + "testing" + "time" + + "github.com/labring/sealos/controllers/pkg/resources" + "go.mongodb.org/mongo-driver/mongo" +) + +func TestMongoDB_GetRechargeAmount(t *testing.T) { + type fields struct { + Client *mongo.Client + AccountDBName string + BillingConn string + PropertiesConn string + Properties *resources.PropertyTypeLS + } + type args struct { + user string + startTime time.Time + endTime time.Time + } + tests := []struct { + name string + fields fields + args args + want int64 + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &MongoDB{ + Client: tt.fields.Client, + AccountDBName: tt.fields.AccountDBName, + BillingConn: tt.fields.BillingConn, + PropertiesConn: tt.fields.PropertiesConn, + Properties: tt.fields.Properties, + } + got, err := m.GetRechargeAmount(tt.args.user, tt.args.startTime, tt.args.endTime) + if (err != nil) != tt.wantErr { + t.Errorf("GetRechargeAmount() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("GetRechargeAmount() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/service/account/docs/docs.go b/service/account/docs/docs.go index a657a336e8b..a78ba78d0d5 100644 --- a/service/account/docs/docs.go +++ b/service/account/docs/docs.go @@ -74,6 +74,174 @@ const docTemplate = `{ } } }, + "/account/v1alpha1/costs/consumption": { + "post": { + "description": "Get user consumption amount within a specified time range", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ConsumptionAmount" + ], + "summary": "Get user consumption amount", + "parameters": [ + { + "description": "User consumption amount request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/helper.UserCostsAmountReq" + } + } + ], + "responses": { + "200": { + "description": "successfully retrieved user consumption amount", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "failed to parse user consumption amount request", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "authenticate error", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "500": { + "description": "failed to get user consumption amount", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/account/v1alpha1/costs/properties": { + "post": { + "description": "Get user properties used amount within a specified time range", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "PropertiesUsedAmount" + ], + "summary": "Get user properties used amount", + "parameters": [ + { + "description": "User properties used amount request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/helper.UserCostsAmountReq" + } + } + ], + "responses": { + "200": { + "description": "successfully retrieved user properties used amount", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "failed to parse user properties used amount request", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "authenticate error", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "500": { + "description": "failed to get user properties used amount", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/account/v1alpha1/costs/recharge": { + "post": { + "description": "Get user recharge amount within a specified time range", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "RechargeAmount" + ], + "summary": "Get user recharge amount", + "parameters": [ + { + "description": "User recharge amount request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/helper.UserCostsAmountReq" + } + } + ], + "responses": { + "200": { + "description": "successfully retrieved user recharge amount", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "failed to parse user recharge amount request", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "authenticate error", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "500": { + "description": "failed to get user recharge amount", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, "/account/v1alpha1/namespaces": { "post": { "description": "Get the billing history namespace list from the database", @@ -317,7 +485,7 @@ const docTemplate = `{ var SwaggerInfo = &swag.Spec{ Version: "v1alpha1", Host: "localhost:2333", - BasePath: "/account/v1alpha1", + BasePath: "", Schemes: []string{}, Title: "sealos account service", Description: "Your API description.", diff --git a/service/account/docs/swagger.json b/service/account/docs/swagger.json index 8507abed994..6093e8f806b 100644 --- a/service/account/docs/swagger.json +++ b/service/account/docs/swagger.json @@ -10,7 +10,6 @@ "version": "v1alpha1" }, "host": "localhost:2333", - "basePath": "/account/v1alpha1", "paths": { "/account/v1alpha1/costs": { "post": { @@ -68,6 +67,174 @@ } } }, + "/account/v1alpha1/costs/consumption": { + "post": { + "description": "Get user consumption amount within a specified time range", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ConsumptionAmount" + ], + "summary": "Get user consumption amount", + "parameters": [ + { + "description": "User consumption amount request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/helper.UserCostsAmountReq" + } + } + ], + "responses": { + "200": { + "description": "successfully retrieved user consumption amount", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "failed to parse user consumption amount request", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "authenticate error", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "500": { + "description": "failed to get user consumption amount", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/account/v1alpha1/costs/properties": { + "post": { + "description": "Get user properties used amount within a specified time range", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "PropertiesUsedAmount" + ], + "summary": "Get user properties used amount", + "parameters": [ + { + "description": "User properties used amount request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/helper.UserCostsAmountReq" + } + } + ], + "responses": { + "200": { + "description": "successfully retrieved user properties used amount", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "failed to parse user properties used amount request", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "authenticate error", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "500": { + "description": "failed to get user properties used amount", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/account/v1alpha1/costs/recharge": { + "post": { + "description": "Get user recharge amount within a specified time range", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "RechargeAmount" + ], + "summary": "Get user recharge amount", + "parameters": [ + { + "description": "User recharge amount request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/helper.UserCostsAmountReq" + } + } + ], + "responses": { + "200": { + "description": "successfully retrieved user recharge amount", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "400": { + "description": "failed to parse user recharge amount request", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "authenticate error", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "500": { + "description": "failed to get user recharge amount", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, "/account/v1alpha1/namespaces": { "post": { "description": "Get the billing history namespace list from the database", diff --git a/service/account/docs/swagger.yaml b/service/account/docs/swagger.yaml index 058411c2664..b0643094b5d 100644 --- a/service/account/docs/swagger.yaml +++ b/service/account/docs/swagger.yaml @@ -1,4 +1,3 @@ -basePath: /account/v1alpha1 definitions: common.PropertyQuery: properties: @@ -144,6 +143,120 @@ paths: summary: Get user costs tags: - Costs + /account/v1alpha1/costs/consumption: + post: + consumes: + - application/json + description: Get user consumption amount within a specified time range + parameters: + - description: User consumption amount request + in: body + name: request + required: true + schema: + $ref: '#/definitions/helper.UserCostsAmountReq' + produces: + - application/json + responses: + "200": + description: successfully retrieved user consumption amount + schema: + additionalProperties: true + type: object + "400": + description: failed to parse user consumption amount request + schema: + additionalProperties: true + type: object + "401": + description: authenticate error + schema: + additionalProperties: true + type: object + "500": + description: failed to get user consumption amount + schema: + additionalProperties: true + type: object + summary: Get user consumption amount + tags: + - ConsumptionAmount + /account/v1alpha1/costs/properties: + post: + consumes: + - application/json + description: Get user properties used amount within a specified time range + parameters: + - description: User properties used amount request + in: body + name: request + required: true + schema: + $ref: '#/definitions/helper.UserCostsAmountReq' + produces: + - application/json + responses: + "200": + description: successfully retrieved user properties used amount + schema: + additionalProperties: true + type: object + "400": + description: failed to parse user properties used amount request + schema: + additionalProperties: true + type: object + "401": + description: authenticate error + schema: + additionalProperties: true + type: object + "500": + description: failed to get user properties used amount + schema: + additionalProperties: true + type: object + summary: Get user properties used amount + tags: + - PropertiesUsedAmount + /account/v1alpha1/costs/recharge: + post: + consumes: + - application/json + description: Get user recharge amount within a specified time range + parameters: + - description: User recharge amount request + in: body + name: request + required: true + schema: + $ref: '#/definitions/helper.UserCostsAmountReq' + produces: + - application/json + responses: + "200": + description: successfully retrieved user recharge amount + schema: + additionalProperties: true + type: object + "400": + description: failed to parse user recharge amount request + schema: + additionalProperties: true + type: object + "401": + description: authenticate error + schema: + additionalProperties: true + type: object + "500": + description: failed to get user recharge amount + schema: + additionalProperties: true + type: object + summary: Get user recharge amount + tags: + - RechargeAmount /account/v1alpha1/namespaces: post: consumes: diff --git a/service/account/helper/common.go b/service/account/helper/common.go index f4541c2d497..d1157b70383 100644 --- a/service/account/helper/common.go +++ b/service/account/helper/common.go @@ -4,7 +4,10 @@ const ( GROUP = "/account/v1alpha1" GetHistoryNamespaces = "/namespaces" GetProperties = "/properties" - GetUserCosts = "/usercosts" + GetRechargeAmount = "/costs/recharge" + GetConsumptionAmount = "/costs/consumption" + GetPropertiesUsed = "/costs/properties" + GetUserCosts = "/costs" ) // env diff --git a/service/account/helper/request.go b/service/account/helper/request.go index 21f950559af..83e9ca1e0bd 100644 --- a/service/account/helper/request.go +++ b/service/account/helper/request.go @@ -2,6 +2,7 @@ package helper import ( "fmt" + "strings" "time" "github.com/labring/sealos/service/account/common" @@ -89,5 +90,6 @@ func ParseUserCostsAmountReq(c *gin.Context) (*UserCostsAmountReq, error) { if userCosts.TimeRange.EndTime.After(time.Now()) { userCosts.TimeRange.EndTime = time.Now() } + userCosts.Owner = strings.TrimPrefix(userCosts.Owner, "ns-") return userCosts, nil } diff --git a/service/account/main.go b/service/account/main.go index 2924855a6d6..e89a2e627d8 100644 --- a/service/account/main.go +++ b/service/account/main.go @@ -10,7 +10,7 @@ import ( // @termsOfService https://cloud.sealos.io // @contact.email bxy4543@gmail.com // @host localhost:2333 -// @BasePath /account/v1alpha1 +// @BasePath func main() { router.RegisterPayRouter() } diff --git a/service/account/router/router.go b/service/account/router/router.go index 28ec60bd16a..fb611ab14dc 100644 --- a/service/account/router/router.go +++ b/service/account/router/router.go @@ -7,6 +7,8 @@ import ( "os/signal" "syscall" + "github.com/labring/sealos/controllers/pkg/utils/env" + "github.com/labring/sealos/service/account/docs" "github.com/labring/sealos/service/account/dao" @@ -27,13 +29,15 @@ func RegisterPayRouter() { if err := dao.InitDB(); err != nil { log.Fatalf("Error initializing database: %v", err) } - // /account/v1alpha1/{/namespaces | /properties | /costs} + // /account/v1alpha1/{/namespaces | /properties | {/costs | /costs/recharge | /costs/consumption | /costs/properties}} router.Group(helper.GROUP). POST(helper.GetHistoryNamespaces, api.GetBillingHistoryNamespaceList). POST(helper.GetProperties, api.GetProperties). - POST(helper.GetUserCosts, api.GetCosts) - - docs.SwaggerInfo.BasePath = helper.GROUP + POST(helper.GetUserCosts, api.GetCosts). + POST(helper.GetRechargeAmount, api.GetRechargeAmount). + POST(helper.GetConsumptionAmount, api.GetConsumptionAmount). + POST(helper.GetPropertiesUsed, api.GetPropertiesUsedAmount) + docs.SwaggerInfo.Host = env.GetEnvWithDefault("SWAGGER_HOST", "localhost:2333") router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) // Create a buffered channel interrupt and use the signal.