mirror of
https://github.com/mattermost/mattermost.git
synced 2026-11-01 09:28:09 -06:00
Remove unused cloud invoice endpoints (#39523)
* Remove unused cloud invoice endpoints
Remove GET /api/v4/cloud/subscription/invoices and
/invoices/{invoice_id}/pdf, their CloudInterface methods and the
Client4.GetInvoicesForSubscription method. Mark the invoice model types
as deprecated since server/public is a published module.
Co-authored-by: Nick Misasi <nick13misasi@gmail.com>
* Clarify deprecation notes on cloud invoice model types
Co-authored-by: Nick Misasi <nick13misasi@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
10 files changed
+19
-298
No files matched your search
@@ -215,69 +215,6 @@
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"501":
|
||||
$ref: "#/components/responses/NotImplemented"
|
||||
/api/v4/cloud/subscription/invoices:
|
||||
get:
|
||||
tags:
|
||||
- cloud
|
||||
summary: Get cloud subscription invoices
|
||||
description: >
|
||||
Retrieves the invoices for the subscription bound to this installation.
|
||||
|
||||
##### Permissions
|
||||
|
||||
Must have `manage_system` permission and be licensed for Cloud.
|
||||
|
||||
__Minimum server version__: 5.30
|
||||
__Note:__ This is intended for internal use and is subject to change.
|
||||
operationId: GetInvoicesForSubscription
|
||||
responses:
|
||||
"200":
|
||||
description: Subscription invoices returned successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Invoice"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"501":
|
||||
$ref: "#/components/responses/NotImplemented"
|
||||
/api/v4/cloud/subscription/invoices/{invoice_id}/pdf:
|
||||
get:
|
||||
tags:
|
||||
- cloud
|
||||
summary: Get cloud invoice PDF
|
||||
description: >
|
||||
Retrieves the PDF for the invoice passed as parameter
|
||||
|
||||
##### Permissions
|
||||
|
||||
Must have `manage_system` permission and be licensed for Cloud.
|
||||
|
||||
__Minimum server version__: 5.30
|
||||
__Note:__ This is intended for internal use and is subject to change.
|
||||
operationId: GetInvoiceForSubscriptionAsPdf
|
||||
parameters:
|
||||
- name: invoice_id
|
||||
in: path
|
||||
description: Invoice ID
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"501":
|
||||
$ref: "#/components/responses/NotImplemented"
|
||||
/api/v4/hosted_customer/signup_available:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -3676,56 +3676,6 @@ components:
|
||||
type: integer
|
||||
is_paid_tier:
|
||||
type: string
|
||||
Invoice:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
number:
|
||||
type: string
|
||||
create_at:
|
||||
type: integer
|
||||
format: int64
|
||||
total:
|
||||
type: integer
|
||||
format: int64
|
||||
tax:
|
||||
type: integer
|
||||
format: int64
|
||||
status:
|
||||
type: string
|
||||
period_start:
|
||||
type: integer
|
||||
format: int64
|
||||
period_end:
|
||||
type: integer
|
||||
format: int64
|
||||
subscription_id:
|
||||
type: string
|
||||
item:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/InvoiceLineItem"
|
||||
InvoiceLineItem:
|
||||
type: object
|
||||
properties:
|
||||
price_id:
|
||||
type: string
|
||||
total:
|
||||
type: integer
|
||||
format: int64
|
||||
quantity:
|
||||
type: integer
|
||||
format: int64
|
||||
price_per_unit:
|
||||
type: integer
|
||||
format: int64
|
||||
description:
|
||||
type: string
|
||||
metadata:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
Group:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -4,16 +4,12 @@
|
||||
package api4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/v8/platform/shared/web"
|
||||
)
|
||||
|
||||
func (api *API) InitCloud() {
|
||||
@@ -27,8 +23,6 @@ func (api *API) InitCloud() {
|
||||
|
||||
// GET /api/v4/cloud/subscription
|
||||
api.BaseRoutes.Cloud.Handle("/subscription", api.APISessionRequired(getSubscription)).Methods(http.MethodGet)
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/invoices", api.APISessionRequired(getInvoicesForSubscription)).Methods(http.MethodGet)
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/invoices/{invoice_id:[_A-Za-z0-9]+}/pdf", api.APISessionRequiredGzip(getSubscriptionInvoicePDF)).Methods(http.MethodGet)
|
||||
|
||||
// GET /api/v4/cloud/validate-business-email
|
||||
api.BaseRoutes.Cloud.Handle("/validate-business-email", api.APISessionRequired(validateBusinessEmail)).Methods(http.MethodPost)
|
||||
@@ -372,79 +366,6 @@ func getInstallation(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func getInvoicesForSubscription(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
ensured := ensureCloudInterface(c, "Api4.getInvoicesForSubscription")
|
||||
if !ensured {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getInvoicesForSubscription", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadBilling) {
|
||||
c.SetPermissionError(model.PermissionSysconsoleReadBilling)
|
||||
return
|
||||
}
|
||||
|
||||
invoices, appErr := c.App.Cloud().GetInvoicesForSubscription(c.AppContext.Session().UserId)
|
||||
if appErr != nil {
|
||||
c.Err = model.NewAppError("Api4.getInvoicesForSubscription", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(appErr)
|
||||
return
|
||||
}
|
||||
|
||||
json, err := json.Marshal(invoices)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("Api4.getInvoicesForSubscription", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := w.Write(json); err != nil {
|
||||
c.Logger.Warn("Error while writing response", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
func getSubscriptionInvoicePDF(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
ensured := ensureCloudInterface(c, "Api4.getSubscriptionInvoicePDF")
|
||||
if !ensured {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.getSubscriptionInvoicePDF", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
c.RequireInvoiceId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadBilling) {
|
||||
c.SetPermissionError(model.PermissionSysconsoleReadBilling)
|
||||
return
|
||||
}
|
||||
|
||||
pdfData, filename, appErr := c.App.Cloud().GetInvoicePDF(c.AppContext.Session().UserId, c.Params.InvoiceId)
|
||||
if appErr != nil {
|
||||
c.Err = model.NewAppError("Api4.getSubscriptionInvoicePDF", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(appErr)
|
||||
return
|
||||
}
|
||||
|
||||
web.WriteFileResponse(
|
||||
filename,
|
||||
"application/pdf",
|
||||
int64(binary.Size(pdfData)),
|
||||
time.Now(),
|
||||
*c.App.Config().ServiceSettings.WebserverMode,
|
||||
bytes.NewReader(pdfData),
|
||||
false,
|
||||
w,
|
||||
r,
|
||||
)
|
||||
}
|
||||
|
||||
func handleCWSWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
ensured := ensureCloudInterface(c, "Api4.handleCWSWebhook")
|
||||
if !ensured {
|
||||
|
||||
@@ -79,7 +79,7 @@ func (api *API) APISessionRequired(h handlerFunc, opts ...APIHandlerOption) http
|
||||
}
|
||||
|
||||
// APISessionRequiredGzip is APISessionRequired without brotli: large file downloads
|
||||
// (e.g. log files, invoice PDFs) compress about as well under gzip as under brotli,
|
||||
// (e.g. log files) compress about as well under gzip as under brotli,
|
||||
// and brotli's memory footprint scales with response size, so these stay on gzip
|
||||
// rather than paying that cost.
|
||||
func (api *API) APISessionRequiredGzip(h handlerFunc, opts ...APIHandlerOption) http.Handler {
|
||||
|
||||
@@ -790,18 +790,6 @@ func (c *Context) RequireBotUserId() *Context {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) RequireInvoiceId() *Context {
|
||||
if c.Err != nil {
|
||||
return c
|
||||
}
|
||||
|
||||
if len(c.Params.InvoiceId) != 27 && c.Params.InvoiceId != model.UpcomingInvoice {
|
||||
c.SetInvalidURLParam("invoice_id")
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) RequireContentReviewerId() *Context {
|
||||
if c.Err != nil {
|
||||
return c
|
||||
|
||||
@@ -121,9 +121,6 @@ type Params struct {
|
||||
// Views
|
||||
ViewId string
|
||||
|
||||
// Cloud
|
||||
InvoiceId string
|
||||
|
||||
// Custom Profile Attributes
|
||||
FieldId string
|
||||
|
||||
@@ -191,7 +188,6 @@ func ParamsFromRequest(r *http.Request) *Params {
|
||||
params.SchemeId = props["scheme_id"]
|
||||
params.GroupId = props["group_id"]
|
||||
params.RemoteId = props["remote_id"]
|
||||
params.InvoiceId = props["invoice_id"]
|
||||
params.OutgoingOAuthConnectionID = props["outgoing_oauth_connection_id"]
|
||||
params.ExcludeOffline, _ = strconv.ParseBool(query.Get("exclude_offline"))
|
||||
params.InChannel = query.Get("in_channel")
|
||||
|
||||
@@ -18,8 +18,6 @@ type CloudInterface interface {
|
||||
GetCloudCustomer(userID string) (*model.CloudCustomer, error)
|
||||
|
||||
GetSubscription(userID string) (*model.Subscription, error)
|
||||
GetInvoicesForSubscription(userID string) ([]*model.Invoice, error)
|
||||
GetInvoicePDF(userID, invoiceID string) ([]byte, string, error)
|
||||
|
||||
ChangeSubscription(userID, subscriptionID string, subscriptionChange *model.SubscriptionChange) (*model.Subscription, error)
|
||||
|
||||
|
||||
@@ -322,73 +322,6 @@ func (_m *CloudInterface) GetInstallation(userID string) (*model.Installation, e
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetInvoicePDF provides a mock function with given fields: userID, invoiceID
|
||||
func (_m *CloudInterface) GetInvoicePDF(userID string, invoiceID string) ([]byte, string, error) {
|
||||
ret := _m.Called(userID, invoiceID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetInvoicePDF")
|
||||
}
|
||||
|
||||
var r0 []byte
|
||||
var r1 string
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(0).(func(string, string) ([]byte, string, error)); ok {
|
||||
return rf(userID, invoiceID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string, string) []byte); ok {
|
||||
r0 = rf(userID, invoiceID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string, string) string); ok {
|
||||
r1 = rf(userID, invoiceID)
|
||||
} else {
|
||||
r1 = ret.Get(1).(string)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(2).(func(string, string) error); ok {
|
||||
r2 = rf(userID, invoiceID)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// GetInvoicesForSubscription provides a mock function with given fields: userID
|
||||
func (_m *CloudInterface) GetInvoicesForSubscription(userID string) ([]*model.Invoice, error) {
|
||||
ret := _m.Called(userID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetInvoicesForSubscription")
|
||||
}
|
||||
|
||||
var r0 []*model.Invoice
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string) ([]*model.Invoice, error)); ok {
|
||||
return rf(userID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string) []*model.Invoice); ok {
|
||||
r0 = rf(userID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.Invoice)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(userID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetSelfHostedProducts provides a mock function with given fields: userID
|
||||
func (_m *CloudInterface) GetSelfHostedProducts(userID string) ([]*model.Product, error) {
|
||||
ret := _m.Called(userID)
|
||||
|
||||
@@ -7478,15 +7478,6 @@ func (c *Client4) GetSubscription(ctx context.Context) (*Subscription, *Response
|
||||
return DecodeJSONFromResponse[*Subscription](r)
|
||||
}
|
||||
|
||||
func (c *Client4) GetInvoicesForSubscription(ctx context.Context) ([]*Invoice, *Response, error) {
|
||||
r, err := c.doAPIGet(ctx, c.cloudRoute().Join("subscription", "invoices"), "")
|
||||
if err != nil {
|
||||
return nil, BuildResponse(r), err
|
||||
}
|
||||
defer closeBody(r)
|
||||
return DecodeJSONFromResponse[[]*Invoice](r)
|
||||
}
|
||||
|
||||
func (c *Client4) ListImports(ctx context.Context) ([]string, *Response, error) {
|
||||
r, err := c.doAPIGet(ctx, c.importsRoute(), "")
|
||||
if err != nil {
|
||||
|
||||
@@ -18,6 +18,7 @@ const (
|
||||
EventTypeTriggerDelinquencyEmail = "trigger-delinquency-email"
|
||||
)
|
||||
|
||||
// Deprecated: The cloud subscription invoice endpoints have been removed.
|
||||
const UpcomingInvoice = "upcoming"
|
||||
|
||||
var MockCWS string
|
||||
@@ -170,17 +171,19 @@ type PaymentMethod struct {
|
||||
|
||||
// Subscription model represents a subscription on the system.
|
||||
type Subscription struct {
|
||||
ID string `json:"id"`
|
||||
CustomerID string `json:"customer_id"`
|
||||
ProductID string `json:"product_id"`
|
||||
AddOns []string `json:"add_ons"`
|
||||
StartAt int64 `json:"start_at"`
|
||||
EndAt int64 `json:"end_at"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
Seats int `json:"seats"`
|
||||
Status string `json:"status"`
|
||||
DNS string `json:"dns"`
|
||||
LastInvoice *Invoice `json:"last_invoice"`
|
||||
ID string `json:"id"`
|
||||
CustomerID string `json:"customer_id"`
|
||||
ProductID string `json:"product_id"`
|
||||
AddOns []string `json:"add_ons"`
|
||||
StartAt int64 `json:"start_at"`
|
||||
EndAt int64 `json:"end_at"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
Seats int `json:"seats"`
|
||||
Status string `json:"status"`
|
||||
DNS string `json:"dns"`
|
||||
// Deprecated: Retained for compatibility; the cloud subscription invoice endpoints have been removed.
|
||||
LastInvoice *Invoice `json:"last_invoice"`
|
||||
// Deprecated: Retained for compatibility; the cloud subscription invoice endpoints have been removed.
|
||||
UpcomingInvoice *Invoice `json:"upcoming_invoice"`
|
||||
IsFreeTrial string `json:"is_free_trial"`
|
||||
TrialEndAt int64 `json:"trial_end_at"`
|
||||
@@ -227,6 +230,8 @@ func (s *Subscription) GetWorkSpaceNameFromDNS() string {
|
||||
}
|
||||
|
||||
// Invoice model represents a cloud invoice
|
||||
//
|
||||
// Deprecated: The cloud subscription invoice endpoints have been removed.
|
||||
type Invoice struct {
|
||||
ID string `json:"id"`
|
||||
Number string `json:"number"`
|
||||
@@ -243,6 +248,8 @@ type Invoice struct {
|
||||
}
|
||||
|
||||
// InvoiceLineItem model represents a cloud invoice lineitem tied to an invoice.
|
||||
//
|
||||
// Deprecated: The cloud subscription invoice endpoints have been removed.
|
||||
type InvoiceLineItem struct {
|
||||
PriceID string `json:"price_id"`
|
||||
Total int64 `json:"total"`
|
||||
|
||||
Reference in new issue
Block a user