Merge branch 'master' of github.com:mattermost/mattermost-server into MM-47853-true-up-review-telemetry-off-non-air-gapped
Этот коммит содержится в:
@@ -80,7 +80,6 @@ func getSubscription(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
Seats: 0,
|
||||
Status: "",
|
||||
DNS: "",
|
||||
IsPaidTier: "",
|
||||
LastInvoice: &model.Invoice{},
|
||||
DelinquentSince: subscription.DelinquentSince,
|
||||
}
|
||||
|
||||
@@ -124,7 +124,6 @@ func Test_GetSubscription(t *testing.T) {
|
||||
Seats: 10,
|
||||
IsFreeTrial: "true",
|
||||
DNS: "some.dns.server",
|
||||
IsPaidTier: "false",
|
||||
TrialEndAt: 2000000000,
|
||||
LastInvoice: &model.Invoice{},
|
||||
DelinquentSince: &deliquencySince,
|
||||
@@ -141,7 +140,6 @@ func Test_GetSubscription(t *testing.T) {
|
||||
Seats: 0,
|
||||
IsFreeTrial: "true",
|
||||
DNS: "",
|
||||
IsPaidTier: "",
|
||||
TrialEndAt: 2000000000,
|
||||
LastInvoice: &model.Invoice{},
|
||||
DelinquentSince: &deliquencySince,
|
||||
@@ -209,7 +207,6 @@ func Test_requestTrial(t *testing.T) {
|
||||
CreateAt: 1000000000,
|
||||
Seats: 10,
|
||||
DNS: "some.dns.server",
|
||||
IsPaidTier: "false",
|
||||
}
|
||||
|
||||
newValidBusinessEmail := model.StartCloudTrialRequest{Email: ""}
|
||||
|
||||
@@ -1185,8 +1185,8 @@ func restoreGroup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToGroup(*c.AppContext.Session(), c.Params.GroupId, model.PermissionDeleteCustomGroup) {
|
||||
c.SetPermissionError(model.PermissionDeleteCustomGroup)
|
||||
if !c.App.SessionHasPermissionToGroup(*c.AppContext.Session(), c.Params.GroupId, model.PermissionRestoreCustomGroup) {
|
||||
c.SetPermissionError(model.PermissionRestoreCustomGroup)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -231,7 +231,13 @@ func TestUndeleteGroup(t *testing.T) {
|
||||
_, response, err := th.Client.DeleteGroup(validGroup.Id)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, response)
|
||||
th.RemovePermissionFromRole(model.PermissionRestoreCustomGroup.Id, model.SystemUserRoleId)
|
||||
// shouldn't allow restoring unless user has required permission
|
||||
_, response, err = th.Client.RestoreGroup(validGroup.Id, "")
|
||||
require.Error(t, err)
|
||||
CheckForbiddenStatus(t, response)
|
||||
|
||||
th.AddPermissionToRole(model.PermissionRestoreCustomGroup.Id, model.SystemUserRoleId)
|
||||
_, response, err = th.Client.RestoreGroup(validGroup.Id, "")
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, response)
|
||||
|
||||
@@ -4,18 +4,35 @@
|
||||
package api4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
"github.com/mattermost/mattermost-server/v6/utils"
|
||||
)
|
||||
|
||||
// APIs for self-hosted workspaces to communicate with the backing customer & payments system.
|
||||
// Endpoints for cloud installations should not go in this file.
|
||||
func (api *API) InitHostedCustomer() {
|
||||
|
||||
// POST /api/v4/hosted_customer/available
|
||||
api.BaseRoutes.HostedCustomer.Handle("/signup_available", api.APISessionRequired(handleSignupAvailable)).Methods("GET")
|
||||
// POST /api/v4/hosted_customer/bootstrap
|
||||
api.BaseRoutes.HostedCustomer.Handle("/bootstrap", api.APISessionRequired(selfHostedBootstrap)).Methods("POST")
|
||||
// POST /api/v4/hosted_customer/customer
|
||||
api.BaseRoutes.HostedCustomer.Handle("/customer", api.APISessionRequired(selfHostedCustomer)).Methods("POST")
|
||||
// POST /api/v4/hosted_customer/confirm
|
||||
api.BaseRoutes.HostedCustomer.Handle("/confirm", api.APISessionRequired(selfHostedConfirm)).Methods("POST")
|
||||
// GET /api/v4/hosted_customer/invoices
|
||||
api.BaseRoutes.HostedCustomer.Handle("/invoices", api.APISessionRequired(selfHostedInvoices)).Methods("GET")
|
||||
// GET /api/v4/hosted_customer/invoices/{invoice_id:in_[A-Za-z0-9]+}/pdf
|
||||
api.BaseRoutes.HostedCustomer.Handle("/invoices/{invoice_id:in_[A-Za-z0-9]+}/pdf", api.APISessionRequired(selfHostedInvoicePDF)).Methods("GET")
|
||||
}
|
||||
|
||||
func ensureSelfHostedAdmin(c *Context, where string) {
|
||||
@@ -32,21 +49,22 @@ func ensureSelfHostedAdmin(c *Context, where string) {
|
||||
}
|
||||
}
|
||||
|
||||
func checkSelfHostedFirstTimePurchaseEnabled(c *Context) bool {
|
||||
func checkSelfHostedPurchaseEnabled(c *Context) bool {
|
||||
config := c.App.Config()
|
||||
if config == nil {
|
||||
return false
|
||||
}
|
||||
enabled := config.ServiceSettings.SelfHostedFirstTimePurchase
|
||||
enabled := config.ServiceSettings.SelfHostedPurchase
|
||||
return enabled != nil && *enabled
|
||||
}
|
||||
|
||||
func selfHostedBootstrap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
where := "Api4.selfHostedBootstrap"
|
||||
if !checkSelfHostedFirstTimePurchaseEnabled(c) {
|
||||
const where = "Api4.selfHostedBootstrap"
|
||||
if !checkSelfHostedPurchaseEnabled(c) {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
reset := r.URL.Query().Get("reset") == "true"
|
||||
ensureSelfHostedAdmin(c, where)
|
||||
if c.Err != nil {
|
||||
return
|
||||
@@ -58,7 +76,7 @@ func selfHostedBootstrap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
signupProgress, err := c.App.Cloud().BootstrapSelfHostedSignup(model.BootstrapSelfHostedSignupRequest{Email: user.Email})
|
||||
signupProgress, err := c.App.Cloud().BootstrapSelfHostedSignup(model.BootstrapSelfHostedSignupRequest{Email: user.Email, Reset: reset})
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError)
|
||||
return
|
||||
@@ -71,3 +89,186 @@ func selfHostedBootstrap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
func selfHostedCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
const where = "Api4.selfHostedCustomer"
|
||||
ensureSelfHostedAdmin(c, where)
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
if !checkSelfHostedPurchaseEnabled(c) {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
bodyBytes, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
var form *model.SelfHostedCustomerForm
|
||||
if err = json.Unmarshal(bodyBytes, &form); err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
user, userErr := c.App.GetUser(c.AppContext.Session().UserId)
|
||||
if userErr != nil {
|
||||
c.Err = userErr
|
||||
return
|
||||
}
|
||||
customerResponse, err := c.App.Cloud().CreateCustomerSelfHostedSignup(*form, user.Email)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
json, err := json.Marshal(customerResponse)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
func selfHostedConfirm(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
const where = "Api4.selfHostedConfirm"
|
||||
ensureSelfHostedAdmin(c, where)
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
if !checkSelfHostedPurchaseEnabled(c) {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
bodyBytes, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
var confirm model.SelfHostedConfirmPaymentMethodRequest
|
||||
err = json.Unmarshal(bodyBytes, &confirm)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.request_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
user, userErr := c.App.GetUser(c.AppContext.Session().UserId)
|
||||
if userErr != nil {
|
||||
c.Err = userErr
|
||||
return
|
||||
}
|
||||
confirmResponse, err := c.App.Cloud().ConfirmSelfHostedSignup(confirm, user.Email)
|
||||
if err != nil {
|
||||
if confirmResponse != nil {
|
||||
c.App.NotifySelfHostedSignupProgress(confirmResponse.Progress, user.Id)
|
||||
}
|
||||
|
||||
if err.Error() == fmt.Sprintf("%d", http.StatusUnprocessableEntity) {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusUnprocessableEntity).Wrap(err)
|
||||
return
|
||||
}
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
license, err := c.App.Srv().Platform().SaveLicense([]byte(confirmResponse.License))
|
||||
// dealing with an AppError
|
||||
if !(reflect.ValueOf(err).Kind() == reflect.Ptr && reflect.ValueOf(err).IsNil()) {
|
||||
if confirmResponse != nil {
|
||||
c.App.NotifySelfHostedSignupProgress(confirmResponse.Progress, user.Id)
|
||||
}
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
clientResponse, err := json.Marshal(model.SelfHostedSignupConfirmClientResponse{
|
||||
License: utils.GetClientLicense(license),
|
||||
Progress: confirmResponse.Progress,
|
||||
})
|
||||
if err != nil {
|
||||
if confirmResponse != nil {
|
||||
c.App.NotifySelfHostedSignupProgress(confirmResponse.Progress, user.Id)
|
||||
}
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
err := c.App.Cloud().ConfirmSelfHostedSignupLicenseApplication()
|
||||
if err != nil {
|
||||
c.Logger.Warn("Unable to confirm license application", mlog.Err(err))
|
||||
}
|
||||
}()
|
||||
|
||||
_, _ = w.Write(clientResponse)
|
||||
}
|
||||
|
||||
func handleSignupAvailable(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
const where = "Api4.handleSignupAvailable"
|
||||
ensureSelfHostedAdmin(c, where)
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
if !checkSelfHostedPurchaseEnabled(c) {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
if err := c.App.Cloud().SelfHostedSignupAvailable(); err != nil {
|
||||
c.Err = model.NewAppError(where, "api.server.hosted_signup_unavailable.error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func selfHostedInvoices(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
const where = "Api4.selfHostedInvoices"
|
||||
ensureSelfHostedAdmin(c, where)
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
invoices, err := c.App.Cloud().GetSelfHostedInvoices()
|
||||
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
json, err := json.Marshal(invoices)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
func selfHostedInvoicePDF(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
const where = "Api4.selfHostedInvoicePDF"
|
||||
ensureSelfHostedAdmin(c, where)
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pdfData, filename, appErr := c.App.Cloud().GetSelfHostedInvoicePDF(c.Params.InvoiceId)
|
||||
if appErr != nil {
|
||||
c.Err = model.NewAppError("Api4.getSubscriptionInvoicePDF", "api.cloud.request_error", nil, appErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
writeFileResponse(
|
||||
filename,
|
||||
"application/pdf",
|
||||
int64(binary.Size(pdfData)),
|
||||
time.Now(),
|
||||
*c.App.Config().ServiceSettings.WebserverMode,
|
||||
bytes.NewReader(pdfData),
|
||||
false,
|
||||
w,
|
||||
r,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestSelfHostedBootstrap(t *testing.T) {
|
||||
|
||||
os.Setenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE", "false")
|
||||
defer os.Unsetenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE")
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedFirstTimePurchase = &valFalse })
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedPurchase = &valFalse })
|
||||
th.App.ReloadConfig()
|
||||
|
||||
_, r, err := th.Client.BootstrapSelfHostedSignup(model.BootstrapSelfHostedSignupRequest{Email: th.SystemAdminUser.Email})
|
||||
@@ -45,7 +45,7 @@ func TestSelfHostedBootstrap(t *testing.T) {
|
||||
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
||||
os.Setenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE", "true")
|
||||
defer os.Unsetenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE")
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedFirstTimePurchase = &valTrue })
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedPurchase = &valTrue })
|
||||
th.App.ReloadConfig()
|
||||
|
||||
_, r, err := th.Client.BootstrapSelfHostedSignup(model.BootstrapSelfHostedSignupRequest{Email: th.SystemAdminUser.Email})
|
||||
@@ -62,7 +62,7 @@ func TestSelfHostedBootstrap(t *testing.T) {
|
||||
|
||||
os.Setenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE", "true")
|
||||
defer os.Unsetenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE")
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedFirstTimePurchase = &valTrue })
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedPurchase = &valTrue })
|
||||
th.App.ReloadConfig()
|
||||
|
||||
_, r, err := th.Client.BootstrapSelfHostedSignup(model.BootstrapSelfHostedSignupRequest{Email: th.SystemAdminUser.Email})
|
||||
@@ -79,7 +79,7 @@ func TestSelfHostedBootstrap(t *testing.T) {
|
||||
|
||||
os.Setenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE", "true")
|
||||
defer os.Unsetenv("MM_SERVICESETTINGS_SELFHOSTEDFIRSTTIMEPURCHASE")
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedFirstTimePurchase = &valTrue })
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SelfHostedPurchase = &valTrue })
|
||||
th.App.ReloadConfig()
|
||||
cloud := mocks.CloudInterface{}
|
||||
|
||||
|
||||
@@ -802,7 +802,8 @@ func patchPost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
auditRec := c.MakeAuditRecord("patchPost", audit.Fail)
|
||||
auditRec.AddEventParameter("patch", post)
|
||||
auditRec.AddEventParameter("id", c.Params.PostId)
|
||||
auditRec.AddEventParameter("patch", post.Auditable())
|
||||
defer c.LogAuditRecWithLevel(auditRec, app.LevelContent)
|
||||
|
||||
// Updating the file_ids of a post is not a supported operation and will be ignored
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/app"
|
||||
"github.com/mattermost/mattermost-server/v6/audit"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/services/remotecluster"
|
||||
@@ -194,7 +195,8 @@ func uploadRemoteData(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
defer c.LogAuditRec(auditRec)
|
||||
auditRec.AddEventParameter("upload_id", c.Params.UploadId)
|
||||
|
||||
us, err := c.App.GetUploadSession(c.Params.UploadId)
|
||||
c.AppContext.SetContext(app.WithMaster(c.AppContext.Context()))
|
||||
us, err := c.App.GetUploadSession(c.AppContext, c.Params.UploadId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/app"
|
||||
"github.com/mattermost/mattermost-server/v6/audit"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
@@ -91,7 +92,7 @@ func getUpload(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
us, err := c.App.GetUploadSession(c.Params.UploadId)
|
||||
us, err := c.App.GetUploadSession(c.AppContext, c.Params.UploadId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
@@ -123,7 +124,8 @@ func uploadData(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
defer c.LogAuditRec(auditRec)
|
||||
auditRec.AddEventParameter("upload_id", c.Params.UploadId)
|
||||
|
||||
us, err := c.App.GetUploadSession(c.Params.UploadId)
|
||||
c.AppContext.SetContext(app.WithMaster(c.AppContext.Context()))
|
||||
us, err := c.App.GetUploadSession(c.AppContext, c.Params.UploadId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
|
||||
63
api4/user.go
63
api4/user.go
@@ -662,13 +662,14 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if sort != "" && sort != "last_activity_at" && sort != "create_at" && sort != "status" && sort != "admin" {
|
||||
if sort != "" && sort != "last_activity_at" && sort != "create_at" && sort != "status" && sort != "admin" && sort != "display_name" {
|
||||
c.SetInvalidURLParam("sort")
|
||||
return
|
||||
}
|
||||
|
||||
// Currently only supports sorting on a team
|
||||
// or sort="status" on inChannelId
|
||||
// or sort="display_name" on inGroupId
|
||||
if (sort == "last_activity_at" || sort == "create_at") && (inTeamId == "" || notInTeamId != "" || inChannelId != "" || notInChannelId != "" || withoutTeam != "" || inGroupId != "" || notInGroupId != "") {
|
||||
c.SetInvalidURLParam("sort")
|
||||
return
|
||||
@@ -681,6 +682,10 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.SetInvalidURLParam("sort")
|
||||
return
|
||||
}
|
||||
if sort == "display_name" && (inGroupId == "" || notInGroupId != "" || inTeamId != "" || notInTeamId != "" || inChannelId != "" || notInChannelId != "" || withoutTeam != "") {
|
||||
c.SetInvalidURLParam("sort")
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
withoutTeamBool, _ = strconv.ParseBool(withoutTeam)
|
||||
@@ -693,14 +698,44 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.SetInvalidURLParam("inactive")
|
||||
}
|
||||
|
||||
roleNamesAll := []string{}
|
||||
// MM-47378: validate 'role' related parameters
|
||||
if role != "" || rolesString != "" || channelRolesString != "" || teamRolesString != "" {
|
||||
// fetch all role names
|
||||
rolesAll, err := c.App.GetAllRoles()
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("Api4.getUsers", "api.user.get_users.validation.app_error", nil, "Error fetching roles during validation.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
for _, role := range rolesAll {
|
||||
roleNamesAll = append(roleNamesAll, role.Name)
|
||||
}
|
||||
}
|
||||
roles := []string{}
|
||||
var rolesValid bool
|
||||
if role != "" {
|
||||
roles, rolesValid = model.CleanRoleNames([]string{role})
|
||||
if !rolesValid {
|
||||
c.SetInvalidParam("role")
|
||||
return
|
||||
}
|
||||
roleValid := utils.StringInSlice(role, roleNamesAll)
|
||||
if !roleValid {
|
||||
c.SetInvalidParam("role")
|
||||
return
|
||||
}
|
||||
}
|
||||
if rolesString != "" {
|
||||
roles, rolesValid = model.CleanRoleNames(strings.Split(rolesString, ","))
|
||||
if !rolesValid {
|
||||
c.SetInvalidParam("roles")
|
||||
return
|
||||
}
|
||||
validRoleNames := utils.StringArrayIntersection(roleNamesAll, roles)
|
||||
if len(validRoleNames) != len(roles) {
|
||||
c.SetInvalidParam("roles")
|
||||
return
|
||||
}
|
||||
}
|
||||
channelRoles := []string{}
|
||||
if channelRolesString != "" && inChannelId != "" {
|
||||
@@ -709,6 +744,11 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.SetInvalidParam("channelRoles")
|
||||
return
|
||||
}
|
||||
validRoleNames := utils.StringArrayIntersection(roleNamesAll, channelRoles)
|
||||
if len(validRoleNames) != len(channelRoles) {
|
||||
c.SetInvalidParam("channelRoles")
|
||||
return
|
||||
}
|
||||
}
|
||||
teamRoles := []string{}
|
||||
if teamRolesString != "" && inTeamId != "" {
|
||||
@@ -717,6 +757,11 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.SetInvalidParam("teamRoles")
|
||||
return
|
||||
}
|
||||
validRoleNames := utils.StringArrayIntersection(roleNamesAll, teamRoles)
|
||||
if len(validRoleNames) != len(teamRoles) {
|
||||
c.SetInvalidParam("teamRoles")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
restrictions, appErr := c.App.GetViewUsersRestrictions(c.AppContext.Session().UserId)
|
||||
@@ -829,10 +874,18 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
profiles, _, appErr = c.App.GetGroupMemberUsersPage(inGroupId, c.Params.Page, c.Params.PerPage, userGetOptions.ViewRestrictions)
|
||||
if appErr != nil {
|
||||
c.Err = appErr
|
||||
return
|
||||
if sort == "display_name" {
|
||||
var user *model.User
|
||||
|
||||
user, appErr = c.App.GetUser(c.AppContext.Session().UserId)
|
||||
if appErr != nil {
|
||||
c.Err = appErr
|
||||
return
|
||||
}
|
||||
|
||||
profiles, _, appErr = c.App.GetGroupMemberUsersSortedPage(inGroupId, c.Params.Page, c.Params.PerPage, userGetOptions.ViewRestrictions, c.App.GetNotificationNameFormat(user))
|
||||
} else {
|
||||
profiles, _, appErr = c.App.GetGroupMemberUsersPage(inGroupId, c.Params.Page, c.Params.PerPage, userGetOptions.ViewRestrictions)
|
||||
}
|
||||
} else if notInGroupId != "" {
|
||||
appErr = requireGroupAccess(c, notInGroupId)
|
||||
|
||||
@@ -7,11 +7,13 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/audit"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
"github.com/mattermost/mattermost-server/v6/store"
|
||||
"github.com/mattermost/mattermost-server/v6/utils"
|
||||
)
|
||||
|
||||
func (api *API) InitUserLocal() {
|
||||
@@ -56,7 +58,78 @@ func localGetUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
active := r.URL.Query().Get("active")
|
||||
inactive := r.URL.Query().Get("inactive")
|
||||
role := r.URL.Query().Get("role")
|
||||
rolesString := r.URL.Query().Get("roles")
|
||||
channelRolesString := r.URL.Query().Get("channel_roles")
|
||||
teamRolesString := r.URL.Query().Get("team_roles")
|
||||
sort := r.URL.Query().Get("sort")
|
||||
roleNamesAll := []string{}
|
||||
// MM-47378: validate 'role' related parameters
|
||||
if role != "" || rolesString != "" || channelRolesString != "" || teamRolesString != "" {
|
||||
// fetch all role names
|
||||
rolesAll, err := c.App.GetAllRoles()
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("Api4.getUsers", "api.user.get_users.validation.app_error", nil, "Error fetching roles during validation.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
for _, role := range rolesAll {
|
||||
roleNamesAll = append(roleNamesAll, role.Name)
|
||||
}
|
||||
}
|
||||
|
||||
var roles []string
|
||||
var rolesValid bool
|
||||
|
||||
if role != "" {
|
||||
_, rolesValid = model.CleanRoleNames([]string{role})
|
||||
if !rolesValid {
|
||||
c.SetInvalidParam("role")
|
||||
return
|
||||
}
|
||||
roleValid := utils.StringInSlice(role, roleNamesAll)
|
||||
if !roleValid {
|
||||
c.SetInvalidParam("role")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if rolesString != "" {
|
||||
roles, rolesValid = model.CleanRoleNames(strings.Split(rolesString, ","))
|
||||
if !rolesValid {
|
||||
c.SetInvalidParam("roles")
|
||||
return
|
||||
}
|
||||
validRoleNames := utils.StringArrayIntersection(roleNamesAll, roles)
|
||||
if len(validRoleNames) != len(roles) {
|
||||
c.SetInvalidParam("roles")
|
||||
return
|
||||
}
|
||||
}
|
||||
var channelRoles []string
|
||||
if channelRolesString != "" && inChannelId != "" {
|
||||
channelRoles, rolesValid = model.CleanRoleNames(strings.Split(channelRolesString, ","))
|
||||
if !rolesValid {
|
||||
c.SetInvalidParam("channelRoles")
|
||||
return
|
||||
}
|
||||
validRoleNames := utils.StringArrayIntersection(roleNamesAll, channelRoles)
|
||||
if len(validRoleNames) != len(channelRoles) {
|
||||
c.SetInvalidParam("channelRoles")
|
||||
return
|
||||
}
|
||||
}
|
||||
var teamRoles []string
|
||||
if teamRolesString != "" && inTeamId != "" {
|
||||
teamRoles, rolesValid = model.CleanRoleNames(strings.Split(teamRolesString, ","))
|
||||
if !rolesValid {
|
||||
c.SetInvalidParam("teamRoles")
|
||||
return
|
||||
}
|
||||
validRoleNames := utils.StringArrayIntersection(roleNamesAll, teamRoles)
|
||||
if len(validRoleNames) != len(teamRoles) {
|
||||
c.SetInvalidParam("teamRoles")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if notInChannelId != "" && inTeamId == "" {
|
||||
c.SetInvalidURLParam("team_id")
|
||||
|
||||
@@ -2410,6 +2410,20 @@ func TestGetUsers(t *testing.T) {
|
||||
// Check default params for page and per_page
|
||||
_, err = client.DoAPIGet("/users", "")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check role params validity
|
||||
_, _, err = client.GetUsersWithCustomQueryParameters(0, 5, "in_channel=random_channel_id&channel_roles=random_role_doesnt_exist", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, err.Error(), ": Invalid or missing channelRoles in request body.")
|
||||
_, _, err = client.GetUsersWithCustomQueryParameters(0, 5, "in_team=random_channel_id&team_roles=random_role_doesnt_exist", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, err.Error(), ": Invalid or missing teamRoles in request body.")
|
||||
_, _, err = client.GetUsersWithCustomQueryParameters(0, 5, "roles=random_role_doesnt_exist%2Csystem_user", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, err.Error(), ": Invalid or missing roles in request body.")
|
||||
_, _, err = client.GetUsersWithCustomQueryParameters(0, 5, "role=random_role_doesnt_exist", "")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, err.Error(), ": Invalid or missing role in request body.")
|
||||
})
|
||||
|
||||
th.Client.Logout()
|
||||
@@ -2823,6 +2837,64 @@ func TestGetUsersInGroup(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetUsersInGroupByDisplayName(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
id := model.NewId()
|
||||
group, appErr := th.App.CreateGroup(&model.Group{
|
||||
DisplayName: "dn-foo_" + id,
|
||||
Name: model.NewString("name" + id),
|
||||
Source: model.GroupSourceLdap,
|
||||
Description: "description_" + id,
|
||||
RemoteId: model.NewString(model.NewId()),
|
||||
})
|
||||
assert.Nil(t, appErr)
|
||||
|
||||
user1, err := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "aaa", Password: "test-password-1", Username: "zzz", Roles: model.SystemUserRoleId})
|
||||
assert.Nil(t, err)
|
||||
|
||||
user2, err := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Password: "test-password-2", Username: "bbb", Roles: model.SystemUserRoleId})
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = th.App.UpsertGroupMember(group.Id, user1.Id)
|
||||
assert.Nil(t, err)
|
||||
_, err = th.App.UpsertGroupMember(group.Id, user2.Id)
|
||||
assert.Nil(t, err)
|
||||
|
||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.PrivacySettings.ShowFullName = true
|
||||
})
|
||||
|
||||
preference := model.Preference{
|
||||
UserId: th.SystemAdminUser.Id,
|
||||
Category: model.PreferenceCategoryDisplaySettings,
|
||||
Name: model.PreferenceNameNameFormat,
|
||||
Value: model.ShowUsername,
|
||||
}
|
||||
|
||||
err = th.App.UpdatePreferences(th.SystemAdminUser.Id, model.Preferences{preference})
|
||||
assert.Nil(t, err)
|
||||
|
||||
t.Run("Returns users in group in right order for username", func(t *testing.T) {
|
||||
users, _, err := th.SystemAdminClient.GetUsersInGroupByDisplayName(group.Id, 0, 1, "")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, users[0].Id, user2.Id)
|
||||
})
|
||||
|
||||
preference.Value = model.ShowNicknameFullName
|
||||
err = th.App.UpdatePreferences(th.SystemAdminUser.Id, model.Preferences{preference})
|
||||
assert.Nil(t, err)
|
||||
|
||||
t.Run("Returns users in group in right order for nickname", func(t *testing.T) {
|
||||
users, _, err := th.SystemAdminClient.GetUsersInGroupByDisplayName(group.Id, 0, 1, "")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, users[0].Id, user1.Id)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestUpdateUserMfa(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
Ссылка в новой задаче
Block a user