[CLD-6678] Various improvements for IP filtering feature (#25485)

* Add GetInstallation function, allow IP Filtering page to fetch installation state, other fixes for IP filter feature

* Fix pipelines

* Run make build-templates

* Fixing i18n

* Fix openapi docs

* Fix openapi docs again

* make build-templates

* Update test to ensure that spinner is removed after installation becomes stable

* Fix types, style

* update openapi because I can't validate locally...

* Updates according to Matt's feedback

* Add a limit to number of times installation is requested before an error is displayed

* Make button disable immediately

* Updates based on PR feedback

* A couple missed occurrences of whitespace

* Grammar fix in failed to fetch error

---------

Co-authored-by: Gabe Jackson <3694686+gabrieljackson@users.noreply.github.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Nick Misasi
2023-11-28 09:09:50 -05:00
коммит произвёл GitHub
родитель 894bba81d8
Коммит 95670abcea
16 изменённых файлов: 318 добавлений и 21 удалений

Просмотреть файл

@@ -54,6 +54,9 @@ func (api *API) InitCloud() {
// POST /api/v4/cloud/webhook
api.BaseRoutes.Cloud.Handle("/webhook", api.CloudAPIKeyRequired(handleCWSWebhook)).Methods("POST")
// GET /api/v4/cloud/installation
api.BaseRoutes.Cloud.Handle("/installation", api.APISessionRequired(getInstallation)).Methods("GET")
// GET /api/v4/cloud/cws-health-check
api.BaseRoutes.Cloud.Handle("/check-cws-connection", api.APIHandler(handleCheckCWSConnection)).Methods("GET")
@@ -474,6 +477,29 @@ func getCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write(json)
}
func getInstallation(c *Context, w http.ResponseWriter, r *http.Request) {
ensured := ensureCloudInterface(c, "Api4.getInstallation")
if !ensured {
return
}
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadIPFilters) {
c.SetPermissionError(model.PermissionSysconsoleReadIPFilters)
return
}
installation, err := c.App.Cloud().GetInstallation(c.AppContext.Session().UserId)
if err != nil {
c.Err = model.NewAppError("Api4.getInstallation", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(err)
return
}
if err := json.NewEncoder(w).Encode(installation); err != nil {
c.Err = model.NewAppError("Api4.getInstallation", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
return
}
}
// getLicenseSelfServeStatus makes check for the license in the CWS self-serve portal and establishes if the license is renewable, expandable etc.
func getLicenseSelfServeStatus(c *Context, w http.ResponseWriter, r *http.Request) {
ensured := ensureCloudInterface(c, "Api4.getLicenseSelfServeStatus")

Просмотреть файл

@@ -56,4 +56,5 @@ type CloudInterface interface {
ApplyIPFilters(userID string, ranges *model.AllowedIPRanges) (*model.AllowedIPRanges, error)
GetIPFilters(userID string) (*model.AllowedIPRanges, error)
GetInstallation(userID string) (*model.Installation, error)
}

Просмотреть файл

@@ -395,6 +395,32 @@ func (_m *CloudInterface) GetIPFilters(userID string) (*model.AllowedIPRanges, e
return r0, r1
}
// GetInstallation provides a mock function with given fields: userID
func (_m *CloudInterface) GetInstallation(userID string) (*model.Installation, error) {
ret := _m.Called(userID)
var r0 *model.Installation
var r1 error
if rf, ok := ret.Get(0).(func(string) (*model.Installation, error)); ok {
return rf(userID)
}
if rf, ok := ret.Get(0).(func(string) *model.Installation); ok {
r0 = rf(userID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Installation)
}
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(userID)
} else {
r1 = ret.Error(1)
}
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)

Просмотреть файл

@@ -301,6 +301,12 @@ type CreateSubscriptionRequest struct {
DiscountID string `json:"discount_id"`
}
type Installation struct {
ID string `json:"id"`
State string `json:"state"`
AllowedIPRanges *AllowedIPRanges `json:"allowed_ip_ranges"`
}
type Feedback struct {
Reason string `json:"reason"`
Comments string `json:"comments"`

Просмотреть файл

@@ -367,7 +367,7 @@
<tbody>
<tr>
<td style="width:132px;">
<img alt height="21" src="{{.Props.SiteURL}}/static/images/logo_email_dark.png" style="border:0;display:block;outline:none;text-decoration:none;height:21.76px;width:100%;font-size:13px;" width="132">
<img alt height="21" src="{{.Props.PortalURL}}/static/images/logo_email_dark.png" style="border:0;display:block;outline:none;text-decoration:none;height:21.76px;width:100%;font-size:13px;" width="132">
</td>
</tr>
</tbody>
@@ -441,7 +441,7 @@
<tbody>
<tr>
<td style="width:312px;">
<img alt height="auto" src="{{.Props.SiteURL}}/static/images/forgot_password_illustration.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="312">
<img alt height="auto" src="{{.Props.PortalURL}}/static/images/forgot_password_illustration.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="312">
</td>
</tr>
</tbody>

Просмотреть файл

@@ -4,32 +4,35 @@
</mj-head>
<mj-body css-class="emailBody" background-color="#FFFFFF">
<mj-wrapper mj-class="email">
<mj-include path="./partials/logo.mjml" />
<mj-section padding="0px 0px 40px 0px">
<mj-column>
<mj-image mj-class="logo" src="{{.Props.PortalURL}}/static/images/logo_email_dark.png" />
</mj-column>
</mj-section>
<mj-include path="./partials/header.mjml" />
<mj-section padding="0px">
<mj-column>
<mj-image src="{{.Props.SiteURL}}/static/images/forgot_password_illustration.png" width="312px"
padding="0px" />
<mj-image src="{{.Props.PortalURL}}/static/images/forgot_password_illustration.png" width="312px" padding="0px" />
</mj-column>
</mj-section>
<mj-section padding="40px 0px 40px 0px">
<mj-column>
<mj-text padding-bottom="9px" css-class="footerTitle" padding="0px">
{{.Props.TroubleAccessingTitle}}
{{.Props.TroubleAccessingTitle}}
</mj-text>
<mj-raw>{{if .Props.ActorEmail}}</mj-raw>
<mj-button padding-top="0px" padding-bottom="1px" font-size="14px" line-height="20px" background-color="transparent" color="#1C58D9" href="mailto:{{.Props.ActorEmail}}">
{{.Props.SendAnEmailTo}}
</mj-button>
<mj-divider padding="0" css-class="divider" width="313px" border-width="1px" border-color="#3F4350"/>
<mj-divider padding="0" css-class="divider" width="313px" border-width="1px" border-color="#3F4350" />
<mj-raw>{{end}}</mj-raw>
<mj-raw>{{ if .Props.LogInToCustomerPortal}}</mj-raw>
<mj-button padding-top="6px" padding-bottom="1px" font-size="14px" line-height="20px" background-color="transparent" color="#1C58D9" href="{{.Props.PortalURL}}/console/cloud/ip-filtering">
<mj-button padding-top="6px" padding-bottom="1px" font-size="14px" line-height="20px" background-color="transparent" color="#1C58D9" href="{{.Props.PortalURL}}/console/cloud/ip-filtering">
{{.Props.LogInToCustomerPortal}}
</mj-button>
<mj-divider padding="0px" css-class="divider" width="313px" border-width="1px" border-color="#3F4350"/>
<mj-divider padding="0px" css-class="divider" width="313px" border-width="1px" border-color="#3F4350" />
<mj-raw>{{end}}</mj-raw>
<mj-button padding-top="6px" font-size="14px" line-height="20px" background-color="transparent" color="#1C58D9" href="mailto:{{.Props.SupportEmail}}">
<mj-button padding-top="6px" font-size="14px" line-height="20px" background-color="transparent" color="#1C58D9" href="mailto:{{.Props.SupportEmail}}">
{{.Props.ContactSupport}}
</mj-button>
</mj-column>