Răsfoiți Sursa

add basic redirect integration with billing portal

Alexander Belanger 3 ani în urmă
părinte
comite
4ac2551ae9

+ 100 - 0
api/server/handlers/billing/redirect_billing.go

@@ -0,0 +1,100 @@
+package billing
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type RedirectBillingHandler struct {
+	handlers.PorterHandlerWriter
+}
+
+func NewRedirectBillingHandler(
+	config *config.Config,
+	writer shared.ResultWriter,
+) *RedirectBillingHandler {
+	return &RedirectBillingHandler{
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
+	}
+}
+
+type CreateBillingCookieRequest struct {
+	ProjectID uint `json:"project_id" form:"required"`
+	UserID    uint `json:"user_id" form:"required"`
+}
+
+type CreateBillingCookieResponse struct {
+	Cookie string `json:"cookie"`
+}
+
+func (c *RedirectBillingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	user, _ := r.Context().Value(types.UserScope).(*models.User)
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	// get an internal cookie
+	data := &CreateBillingCookieRequest{
+		ProjectID: proj.ID,
+		UserID:    user.ID,
+	}
+
+	var strData []byte
+	var err error
+
+	if data != nil {
+		strData, err = json.Marshal(data)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+	}
+
+	req, err := http.NewRequest(
+		"POST",
+		fmt.Sprintf("%s/api/v1/private/cookie", c.Config().ServerConf.BillingServerURL),
+		strings.NewReader(string(strData)),
+	)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	req.Header.Set("Content-Type", "application/json; charset=utf-8")
+	req.Header.Set("Accept", "application/json; charset=utf-8")
+	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.Config().ServerConf.BillingPrivateKey))
+
+	httpClient := http.Client{}
+
+	res, err := httpClient.Do(req)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	defer res.Body.Close()
+
+	dst := &CreateBillingCookieResponse{}
+
+	if dst != nil {
+		err = json.NewDecoder(res.Body).Decode(dst)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+	}
+
+	w.Header().Add("Set-Cookie", dst.Cookie)
+	http.Redirect(w, r, c.Config().ServerConf.BillingServerURL, 302)
+}

+ 27 - 0
api/server/router/project.go

@@ -227,6 +227,33 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
+	// GET /api/project/{project_id}/billing/redirect -> billing.NewRedirectBillingHandler
+	redirectBillingEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/billing/redirect",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	redirectBillingHandler := billing.NewRedirectBillingHandler(
+		config,
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: redirectBillingEndpoint,
+		Handler:  redirectBillingHandler,
+		Router:   r,
+	})
+
 	// GET /api/projects/{project_id}/billing -> project.NewProjectGetBillingHandler
 	getBillingEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{

+ 3 - 0
api/server/shared/config/env/envconfs.go

@@ -62,6 +62,9 @@ type ServerConf struct {
 	SlackClientID     string `env:"SLACK_CLIENT_ID"`
 	SlackClientSecret string `env:"SLACK_CLIENT_SECRET"`
 
+	BillingPrivateKey string `env:"BILLING_PRIVATE_KEY"`
+	BillingServerURL  string `env:"BILLING_URL"`
+
 	IronPlansAPIKey    string `env:"IRON_PLANS_API_KEY"`
 	IronPlansServerURL string `env:"IRON_PLANS_SERVER_URL"`
 	WhitelistedUsers   []uint `env:"WHITELISTED_USERS"`