MM-47420 - Add endpoint to fetch selfhosted products (#21678)
* created selfhosted endpoint * make autogenerated mocks * add test * add user id * remove user id requirement * add tests * send user id with request Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ed3f3fec46
Коммит
966456567d
@@ -22,6 +22,8 @@ func (api *API) InitCloud() {
|
||||
// GET /api/v4/cloud/limits
|
||||
api.BaseRoutes.Cloud.Handle("/limits", api.APISessionRequired(getCloudLimits)).Methods("GET")
|
||||
|
||||
api.BaseRoutes.Cloud.Handle("/products/selfhosted", api.APISessionRequired(getSelfHostedProducts)).Methods("GET")
|
||||
|
||||
// POST /api/v4/cloud/payment
|
||||
// POST /api/v4/cloud/payment/confirm
|
||||
api.BaseRoutes.Cloud.Handle("/payment", api.APISessionRequired(createCustomerPayment)).Methods("POST")
|
||||
@@ -276,6 +278,40 @@ func validateWorkspaceBusinessEmail(c *Context, w http.ResponseWriter, r *http.R
|
||||
}
|
||||
}
|
||||
|
||||
func getSelfHostedProducts(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
products, err := c.App.Cloud().GetSelfHostedProducts(c.AppContext.Session().UserId)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("Api4.getSelfHostedProducts", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
byteProductsData, err := json.Marshal(products)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("Api4.getSelfHostedProducts", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadBilling) {
|
||||
sanitizedProducts := []model.UserFacingProduct{}
|
||||
err = json.Unmarshal(byteProductsData, &sanitizedProducts)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("Api4.getSelfHostedProducts", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
byteSanitizedProductsData, err := json.Marshal(sanitizedProducts)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("Api4.getSelfHostedProducts", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(byteSanitizedProductsData)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(byteProductsData)
|
||||
}
|
||||
|
||||
func getCloudProducts(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getCloudProducts", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
|
||||
@@ -651,3 +651,110 @@ func TestGetCloudProducts(t *testing.T) {
|
||||
require.Equal(t, returnedProducts[2].CrossSellsTo, "prod_test2")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetSelfHostedProducts(t *testing.T) {
|
||||
products := []*model.Product{
|
||||
{
|
||||
ID: "prod_test",
|
||||
Name: "Self-Hosted Professional",
|
||||
Description: "Ideal for small companies and departments with data security requirements",
|
||||
PricePerSeat: 10,
|
||||
SKU: "professional",
|
||||
PriceID: "price_1JPXbNI67GP2qpb4VuFdFbwQ",
|
||||
Family: "on-prem",
|
||||
RecurringInterval: model.RecurringIntervalYearly,
|
||||
},
|
||||
{
|
||||
ID: "prod_test2",
|
||||
Name: "Self-Hosted Enterprise",
|
||||
Description: "Built to scale for high-trust organizations and companies in regulated industries.",
|
||||
PricePerSeat: 30,
|
||||
SKU: "enterprise",
|
||||
PriceID: "price_1JPXaVI67GP2qpb4l40bXyRu",
|
||||
Family: "on-prem",
|
||||
RecurringInterval: model.RecurringIntervalYearly,
|
||||
},
|
||||
}
|
||||
|
||||
sanitizedProducts := []*model.Product{
|
||||
{
|
||||
ID: "prod_test",
|
||||
Name: "Self-Hosted Professional",
|
||||
PricePerSeat: 10,
|
||||
SKU: "professional",
|
||||
RecurringInterval: model.RecurringIntervalYearly,
|
||||
},
|
||||
{
|
||||
ID: "prod_test2",
|
||||
Name: "Self-Hosted Enterprise",
|
||||
PricePerSeat: 30,
|
||||
SKU: "enterprise",
|
||||
RecurringInterval: model.RecurringIntervalYearly,
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("get products for admins", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.Client.Login(th.SystemAdminUser.Email, th.SystemAdminUser.Password)
|
||||
|
||||
cloud := mocks.CloudInterface{}
|
||||
cloud.Mock.On("GetSelfHostedProducts", mock.Anything, mock.Anything).Return(products, nil)
|
||||
cloudImpl := th.App.Srv().Cloud
|
||||
defer func() {
|
||||
th.App.Srv().Cloud = cloudImpl
|
||||
}()
|
||||
th.App.Srv().Cloud = &cloud
|
||||
|
||||
returnedProducts, r, err := th.Client.GetSelfHostedProducts()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
|
||||
require.Equal(t, returnedProducts, products)
|
||||
})
|
||||
|
||||
t.Run("get products for non admins", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||
|
||||
cloud := mocks.CloudInterface{}
|
||||
|
||||
cloud.Mock.On("GetSelfHostedProducts", mock.Anything, mock.Anything).Return(products, nil)
|
||||
|
||||
cloudImpl := th.App.Srv().Cloud
|
||||
defer func() {
|
||||
th.App.Srv().Cloud = cloudImpl
|
||||
}()
|
||||
th.App.Srv().Cloud = &cloud
|
||||
|
||||
returnedProducts, r, err := th.Client.GetSelfHostedProducts()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
|
||||
require.Equal(t, returnedProducts, sanitizedProducts)
|
||||
|
||||
// make a more explicit check
|
||||
require.Equal(t, returnedProducts[0].ID, "prod_test")
|
||||
require.Equal(t, returnedProducts[0].Name, "Self-Hosted Professional")
|
||||
require.Equal(t, returnedProducts[0].SKU, "professional")
|
||||
require.Equal(t, returnedProducts[0].PricePerSeat, float64(10))
|
||||
require.Equal(t, returnedProducts[0].Description, "")
|
||||
require.Equal(t, returnedProducts[0].PriceID, "")
|
||||
require.Equal(t, returnedProducts[0].Family, model.SubscriptionFamily(""))
|
||||
require.Equal(t, returnedProducts[0].RecurringInterval, model.RecurringInterval("year"))
|
||||
require.Equal(t, returnedProducts[0].BillingScheme, model.BillingScheme(""))
|
||||
require.Equal(t, returnedProducts[0].CrossSellsTo, "")
|
||||
|
||||
require.Equal(t, returnedProducts[1].ID, "prod_test2")
|
||||
require.Equal(t, returnedProducts[1].Name, "Self-Hosted Enterprise")
|
||||
require.Equal(t, returnedProducts[1].SKU, "enterprise")
|
||||
require.Equal(t, returnedProducts[1].PricePerSeat, float64(30))
|
||||
require.Equal(t, returnedProducts[1].Description, "")
|
||||
require.Equal(t, returnedProducts[1].PriceID, "")
|
||||
require.Equal(t, returnedProducts[1].Family, model.SubscriptionFamily(""))
|
||||
require.Equal(t, returnedProducts[1].RecurringInterval, model.RecurringInterval("year"))
|
||||
require.Equal(t, returnedProducts[1].BillingScheme, model.BillingScheme(""))
|
||||
require.Equal(t, returnedProducts[1].CrossSellsTo, "")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
type CloudInterface interface {
|
||||
GetCloudProduct(userID string, productID string) (*model.Product, error)
|
||||
GetCloudProducts(userID string, includeLegacyProducts bool) ([]*model.Product, error)
|
||||
GetSelfHostedProducts(userID string) ([]*model.Product, error)
|
||||
GetCloudLimits(userID string) (*model.ProductLimits, error)
|
||||
|
||||
CreateCustomerPayment(userID string) (*model.StripeSetupIntent, error)
|
||||
|
||||
@@ -279,6 +279,29 @@ func (_m *CloudInterface) GetLicenseRenewalStatus(userID string, token string) e
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetSelfHostedProducts provides a mock function with given fields: userID
|
||||
func (_m *CloudInterface) GetSelfHostedProducts(userID string) ([]*model.Product, error) {
|
||||
ret := _m.Called(userID)
|
||||
|
||||
var r0 []*model.Product
|
||||
if rf, ok := ret.Get(0).(func(string) []*model.Product); ok {
|
||||
r0 = rf(userID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.Product)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(userID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetSubscription provides a mock function with given fields: userID
|
||||
func (_m *CloudInterface) GetSubscription(userID string) (*model.Subscription, error) {
|
||||
ret := _m.Called(userID)
|
||||
|
||||
@@ -8041,6 +8041,19 @@ func (c *Client4) GetCloudProducts() ([]*Product, *Response, error) {
|
||||
return cloudProducts, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
func (c *Client4) GetSelfHostedProducts() ([]*Product, *Response, error) {
|
||||
r, err := c.DoAPIGet(c.cloudRoute()+"/products/selfhosted", "")
|
||||
if err != nil {
|
||||
return nil, BuildResponse(r), err
|
||||
}
|
||||
defer closeBody(r)
|
||||
|
||||
var products []*Product
|
||||
json.NewDecoder(r.Body).Decode(&products)
|
||||
|
||||
return products, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
func (c *Client4) GetProductLimits() (*ProductLimits, *Response, error) {
|
||||
r, err := c.DoAPIGet(c.cloudRoute()+"/limits", "")
|
||||
if err != nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user