[MM-44307] On Limits Change, archive or restore teams according to the limits (#20247)

Automatic Merge
Этот коммит содержится в:
Nick Misasi
2022-05-24 09:16:24 -04:00
коммит произвёл GitHub
родитель 380a0ef827
Коммит 50d069e86d
13 изменённых файлов: 454 добавлений и 26 удалений

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

@@ -536,7 +536,9 @@ func handleCWSWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
return true return true
}, plugin.OnCloudLimitsUpdatedID) }, plugin.OnCloudLimitsUpdatedID)
} }
c.App.AdjustInProductLimits(event.ProductLimits, event.Subscription)
} }
if err := c.App.Cloud().UpdateSubscriptionFromHook(event.ProductLimits, event.Subscription); err != nil { if err := c.App.Cloud().UpdateSubscriptionFromHook(event.ProductLimits, event.Subscription); err != nil {
c.Err = model.NewAppError("Api4.handleCWSWebhook", "api.cloud.subscription.update_error", nil, err.Error(), http.StatusInternalServerError) c.Err = model.NewAppError("Api4.handleCWSWebhook", "api.cloud.subscription.update_error", nil, err.Error(), http.StatusInternalServerError)
return return

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

@@ -43,6 +43,7 @@ func (api *API) InitTeam() {
api.BaseRoutes.Team.Handle("", api.APISessionRequired(getTeam)).Methods("GET") api.BaseRoutes.Team.Handle("", api.APISessionRequired(getTeam)).Methods("GET")
api.BaseRoutes.Team.Handle("", api.APISessionRequired(updateTeam)).Methods("PUT") api.BaseRoutes.Team.Handle("", api.APISessionRequired(updateTeam)).Methods("PUT")
api.BaseRoutes.Team.Handle("", api.APISessionRequired(deleteTeam)).Methods("DELETE") api.BaseRoutes.Team.Handle("", api.APISessionRequired(deleteTeam)).Methods("DELETE")
api.BaseRoutes.Team.Handle("/except", api.APISessionRequired(softDeleteTeamsExcept)).Methods("DELETE")
api.BaseRoutes.Team.Handle("/patch", api.APISessionRequired(patchTeam)).Methods("PUT") api.BaseRoutes.Team.Handle("/patch", api.APISessionRequired(patchTeam)).Methods("PUT")
api.BaseRoutes.Team.Handle("/restore", api.APISessionRequired(restoreTeam)).Methods("POST") api.BaseRoutes.Team.Handle("/restore", api.APISessionRequired(restoreTeam)).Methods("POST")
api.BaseRoutes.Team.Handle("/privacy", api.APISessionRequired(updateTeamPrivacy)).Methods("PUT") api.BaseRoutes.Team.Handle("/privacy", api.APISessionRequired(updateTeamPrivacy)).Methods("PUT")
@@ -402,6 +403,23 @@ func deleteTeam(c *Context, w http.ResponseWriter, r *http.Request) {
ReturnStatusOK(w) ReturnStatusOK(w)
} }
func softDeleteTeamsExcept(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireTeamId()
if c.Err != nil {
return
}
if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), c.Params.TeamId, model.PermissionManageTeam) {
c.SetPermissionError(model.PermissionManageTeam)
return
}
err := c.App.SoftDeleteAllTeamsExcept(c.Params.TeamId)
if err != nil {
c.Err = err
}
}
func getTeamsForUser(c *Context, w http.ResponseWriter, r *http.Request) { func getTeamsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId() c.RequireUserId()
if c.Err != nil { if c.Err != nil {

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

@@ -387,6 +387,8 @@ type AppIface interface {
AddUserToTeamByTeamId(c *request.Context, teamID string, user *model.User) *model.AppError AddUserToTeamByTeamId(c *request.Context, teamID string, user *model.User) *model.AppError
AddUserToTeamByToken(c *request.Context, userID string, tokenID string) (*model.Team, *model.TeamMember, *model.AppError) AddUserToTeamByToken(c *request.Context, userID string, tokenID string) (*model.Team, *model.TeamMember, *model.AppError)
AdjustImage(file io.Reader) (*bytes.Buffer, *model.AppError) AdjustImage(file io.Reader) (*bytes.Buffer, *model.AppError)
AdjustInProductLimits(limits *model.ProductLimits, subscription *model.Subscription) *model.AppError
AdjustTeamsFromProductLimits(teamLimits *model.TeamsLimits) *model.AppError
AllowOAuthAppAccessToUser(userID string, authRequest *model.AuthorizeRequest) (string, *model.AppError) AllowOAuthAppAccessToUser(userID string, authRequest *model.AuthorizeRequest) (string, *model.AppError)
AppendFile(fr io.Reader, path string) (int64, *model.AppError) AppendFile(fr io.Reader, path string) (int64, *model.AppError)
AsymmetricSigningKey() *ecdsa.PrivateKey AsymmetricSigningKey() *ecdsa.PrivateKey
@@ -1022,6 +1024,7 @@ type AppIface interface {
SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppError SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppError
SetTeamIconFromMultiPartFile(teamID string, file multipart.File) *model.AppError SetTeamIconFromMultiPartFile(teamID string, file multipart.File) *model.AppError
SlackImport(c *request.Context, fileData multipart.File, fileSize int64, teamID string) (*model.AppError, *bytes.Buffer) SlackImport(c *request.Context, fileData multipart.File, fileSize int64, teamID string) (*model.AppError, *bytes.Buffer)
SoftDeleteAllTeamsExcept(teamID string) *model.AppError
SoftDeleteTeam(teamID string) *model.AppError SoftDeleteTeam(teamID string) *model.AppError
Srv() *Server Srv() *Server
SubmitInteractiveDialog(c *request.Context, request model.SubmitDialogRequest) (*model.SubmitDialogResponse, *model.AppError) SubmitInteractiveDialog(c *request.Context, request model.SubmitDialogRequest) (*model.SubmitDialogResponse, *model.AppError)

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

@@ -37,6 +37,17 @@ func (a *App) SendPaymentFailedEmail(failedPayment *model.FailedPayment) *model.
return nil return nil
} }
func (a *App) AdjustInProductLimits(limits *model.ProductLimits, subscription *model.Subscription) *model.AppError {
if limits.Teams != nil && limits.Teams.Active != nil && *limits.Teams.Active > 0 {
err := a.AdjustTeamsFromProductLimits(limits.Teams)
if err != nil {
return err
}
}
return nil
}
func (a *App) SendUpgradeConfirmationEmail() *model.AppError { func (a *App) SendUpgradeConfirmationEmail() *model.AppError {
sysAdmins, e := a.getSysAdminsEmailRecipients() sysAdmins, e := a.getSysAdminsEmailRecipients()
if e != nil { if e != nil {

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

@@ -625,6 +625,50 @@ func (a *OpenTracingAppLayer) AdjustImage(file io.Reader) (*bytes.Buffer, *model
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) AdjustInProductLimits(limits *model.ProductLimits, subscription *model.Subscription) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AdjustInProductLimits")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.AdjustInProductLimits(limits, subscription)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) AdjustTeamsFromProductLimits(teamLimits *model.TeamsLimits) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AdjustTeamsFromProductLimits")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.AdjustTeamsFromProductLimits(teamLimits)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) AllowOAuthAppAccessToUser(userID string, authRequest *model.AuthorizeRequest) (string, *model.AppError) { func (a *OpenTracingAppLayer) AllowOAuthAppAccessToUser(userID string, authRequest *model.AuthorizeRequest) (string, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AllowOAuthAppAccessToUser") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AllowOAuthAppAccessToUser")
@@ -15583,6 +15627,28 @@ func (a *OpenTracingAppLayer) SlackImport(c *request.Context, fileData multipart
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) SoftDeleteAllTeamsExcept(teamID string) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SoftDeleteAllTeamsExcept")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.SoftDeleteAllTeamsExcept(teamID)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) SoftDeleteTeam(teamID string) *model.AppError { func (a *OpenTracingAppLayer) SoftDeleteTeam(teamID string) *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SoftDeleteTeam") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SoftDeleteTeam")

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

@@ -14,6 +14,7 @@ import (
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"net/url" "net/url"
"sort"
"strings" "strings"
"github.com/mattermost/mattermost-server/v6/app/email" "github.com/mattermost/mattermost-server/v6/app/email"
@@ -29,6 +30,106 @@ import (
"github.com/mattermost/mattermost-server/v6/store/sqlstore" "github.com/mattermost/mattermost-server/v6/store/sqlstore"
) )
func (a *App) AdjustTeamsFromProductLimits(teamLimits *model.TeamsLimits) *model.AppError {
maxActiveTeams := *teamLimits.Active
teams, appErr := a.GetAllTeams()
if appErr != nil {
return appErr
}
if teams == nil {
return nil
}
// Sort the list of teams based on their creation date
sort.Slice(teams, func(i, j int) bool {
return teams[i].CreateAt < teams[j].CreateAt
})
var activeTeams []*model.Team
var cloudArchivedTeams []*model.Team
for _, team := range teams {
if team.DeleteAt == 0 {
activeTeams = append(activeTeams, team)
}
if team.DeleteAt > 0 && team.CloudLimitsArchived {
cloudArchivedTeams = append(cloudArchivedTeams, team)
}
}
if len(activeTeams) > maxActiveTeams {
// If there are more active teams than allowed, we must archive them
// Remove the first n elements (where n is the allowed number of teams) so they aren't archived
teamsToArchive := activeTeams[maxActiveTeams:]
for _, team := range teamsToArchive {
cloudLimitsArchived := true
// Archive the remainder
patch := model.TeamPatch{CloudLimitsArchived: &cloudLimitsArchived}
_, err := a.PatchTeam(team.Id, &patch)
if err != nil {
return err
}
err = a.SoftDeleteTeam(team.Id)
if err != nil {
return err
}
}
} else if len(activeTeams) < maxActiveTeams && len(cloudArchivedTeams) > 0 {
// If the number of activeTeams is less than the allowed limit, and there are some cloudArchivedTeams, we can restore these cloudArchivedTeams
activeTeamsBeforeLimit := maxActiveTeams - len(activeTeams)
teamsToRestore := cloudArchivedTeams
// If the number of active teams remaining before the limit is hit is fewer than the number of cloudArchivedTeams, trim the list (still according to CreateAt)
// Otherwise, we can restore all of the cloudArchivedTeams without hitting the limit, so don't filter the list
if activeTeamsBeforeLimit < len(cloudArchivedTeams) {
teamsToRestore = cloudArchivedTeams[:(activeTeamsBeforeLimit)]
}
cloudLimitsArchived := false
patch := &model.TeamPatch{CloudLimitsArchived: &cloudLimitsArchived}
for _, team := range teamsToRestore {
err := a.RestoreTeam(team.Id)
if err != nil {
return err
}
_, err = a.PatchTeam(team.Id, patch)
if err != nil {
return err
}
}
}
return nil
}
func (a *App) SoftDeleteAllTeamsExcept(teamID string) *model.AppError {
teams, appErr := a.GetAllTeams()
if appErr != nil {
return appErr
}
if teams == nil {
return nil
}
cloudLimitsArchived := true
patch := &model.TeamPatch{CloudLimitsArchived: &cloudLimitsArchived}
for _, team := range teams {
if team.Id != teamID {
_, err := a.PatchTeam(team.Id, patch)
if err != nil {
return err
}
err = a.SoftDeleteTeam(team.Id)
if err != nil {
return err
}
}
}
return nil
}
func (a *App) CreateTeam(c *request.Context, team *model.Team) (*model.Team, *model.AppError) { func (a *App) CreateTeam(c *request.Context, team *model.Team) (*model.Team, *model.AppError) {
rteam, err := a.ch.srv.teamService.CreateTeam(team) rteam, err := a.ch.srv.teamService.CreateTeam(team)
if err != nil { if err != nil {

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

@@ -466,6 +466,197 @@ func TestAddUserToTeamByTeamId(t *testing.T) {
} }
func TestSoftDeleteAllTeamsExcept(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
teams := []*model.Team{
{
DisplayName: "team-1",
Name: "team-1",
Email: "foo@foo.com",
Type: model.TeamOpen,
},
}
teamId := ""
for _, create := range teams {
team, err := th.App.CreateTeam(th.Context, create)
require.Nil(t, err)
teamId = team.Id
}
err := th.App.SoftDeleteAllTeamsExcept(teamId)
assert.Nil(t, err)
allTeams, err := th.App.GetAllTeams()
require.Nil(t, err)
for _, team := range allTeams {
if team.Id == teamId {
require.Equal(t, int64(0), team.DeleteAt)
require.Equal(t, false, team.CloudLimitsArchived)
} else {
require.NotEqual(t, int64(0), team.DeleteAt)
require.Equal(t, true, team.CloudLimitsArchived)
}
}
}
func TestAdjustTeamsFromProductLimits(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
teams := []*model.Team{
{
DisplayName: "team-1",
Name: "team-1",
Email: "foo@foo.com",
Type: model.TeamOpen,
},
{
DisplayName: "team-2",
Name: "team-2",
Email: "foo@foo.com",
Type: model.TeamOpen,
},
{
DisplayName: "team-3",
Name: "team-3",
Email: "foo@foo.com",
Type: model.TeamOpen,
},
}
teamIds := []string{}
for _, create := range teams {
team, err := th.App.CreateTeam(th.Context, create)
require.Nil(t, err)
teamIds = append(teamIds, team.Id)
}
t.Run("Should soft delete teams if there are more teams than the limit", func(t *testing.T) {
activeLimit := 1
teamLimits := &model.TeamsLimits{Active: &activeLimit}
err := th.App.AdjustTeamsFromProductLimits(teamLimits)
require.Nil(t, err)
teamsList, err := th.App.GetTeams(teamIds)
require.Nil(t, err)
// Sort the list of teams based on their creation date
sort.Slice(teamsList, func(i, j int) bool {
return teamsList[i].CreateAt < teamsList[j].CreateAt
})
for i := range teamsList {
require.Equal(t, teamsList[i].DisplayName, teams[i].DisplayName)
require.NotEqual(t, 0, teamsList[i].DeleteAt)
require.Equal(t, true, teamsList[i].CloudLimitsArchived)
}
})
t.Run("Should not do anything if the amount of teams is equal to the limit", func(t *testing.T) {
expectedTeamsList, err := th.App.GetAllTeams()
var expectedActiveTeams []*model.Team
var expectedCloudArchivedTeams []*model.Team
for _, team := range expectedTeamsList {
if team.DeleteAt == 0 {
expectedActiveTeams = append(expectedActiveTeams, team)
}
if team.DeleteAt > 0 && team.CloudLimitsArchived {
expectedCloudArchivedTeams = append(expectedCloudArchivedTeams, team)
}
}
require.Nil(t, err)
activeLimit := len(expectedActiveTeams)
teamLimits := &model.TeamsLimits{Active: &activeLimit}
err = th.App.AdjustTeamsFromProductLimits(teamLimits)
require.Nil(t, err)
actualTeamsList, err := th.App.GetAllTeams()
require.Nil(t, err)
var actualActiveTeams []*model.Team
var actualCloudArchivedTeams []*model.Team
for _, team := range actualTeamsList {
if team.DeleteAt == 0 {
actualActiveTeams = append(actualActiveTeams, team)
}
if team.DeleteAt > 0 && team.CloudLimitsArchived {
actualCloudArchivedTeams = append(actualCloudArchivedTeams, team)
}
}
require.Equal(t, len(expectedActiveTeams), len(actualActiveTeams))
require.Equal(t, len(expectedCloudArchivedTeams), len(actualCloudArchivedTeams))
})
t.Run("Should restore archived teams if limit increases", func(t *testing.T) {
activeLimit := 1
teamLimits := &model.TeamsLimits{Active: &activeLimit}
err := th.App.AdjustTeamsFromProductLimits(teamLimits)
require.Nil(t, err)
activeLimit = 10000 // make the limit extremely high so all teams are enabled
teamLimits = &model.TeamsLimits{Active: &activeLimit}
err = th.App.AdjustTeamsFromProductLimits(teamLimits)
require.Nil(t, err)
teamsList, err := th.App.GetTeams(teamIds)
require.Nil(t, err)
// Sort the list of teams based on their creation date
sort.Slice(teamsList, func(i, j int) bool {
return teamsList[i].CreateAt < teamsList[j].CreateAt
})
for i := range teamsList {
require.Equal(t, teamsList[i].DisplayName, teams[i].DisplayName)
require.Equal(t, int64(0), teamsList[i].DeleteAt)
require.Equal(t, false, teamsList[i].CloudLimitsArchived)
}
})
t.Run("Should only restore teams that were archived by cloud limits", func(t *testing.T) {
activeLimit := 1
teamLimits := &model.TeamsLimits{Active: &activeLimit}
err := th.App.AdjustTeamsFromProductLimits(teamLimits)
require.Nil(t, err)
cloudLimitsArchived := false
patch := &model.TeamPatch{CloudLimitsArchived: &cloudLimitsArchived}
team, err := th.App.PatchTeam(teamIds[0], patch)
require.Nil(t, err)
require.Equal(t, false, team.CloudLimitsArchived)
activeLimit = 10000 // make the limit extremely high so all teams are enabled
teamLimits = &model.TeamsLimits{Active: &activeLimit}
err = th.App.AdjustTeamsFromProductLimits(teamLimits)
require.Nil(t, err)
teamsList, err := th.App.GetTeams(teamIds)
require.Nil(t, err)
// Sort the list of teams based on their creation date
sort.Slice(teamsList, func(i, j int) bool {
return teamsList[i].CreateAt < teamsList[j].CreateAt
})
require.NotEqual(t, int64(0), teamsList[0].DeleteAt)
require.Equal(t, int64(0), teamsList[1].DeleteAt)
require.Equal(t, int64(0), teamsList[2].DeleteAt)
})
}
func TestPermanentDeleteTeam(t *testing.T) { func TestPermanentDeleteTeam(t *testing.T) {
th := Setup(t).InitBasic() th := Setup(t).InitBasic()
defer th.TearDown() defer th.TearDown()

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

@@ -0,0 +1,14 @@
SET @preparedStatement = (SELECT IF(
EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Teams'
AND table_schema = DATABASE()
AND column_name = 'CloudLimitsArchived'
),
'ALTER TABLE Teams DROP COLUMN CloudLimitsArchived;',
'SELECT 1'
));
PREPARE alterIfExists FROM @preparedStatement;
EXECUTE alterIfExists;
DEALLOCATE PREPARE alterIfExists;

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

@@ -0,0 +1,14 @@
SET @preparedStatement = (SELECT IF(
NOT EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Teams'
AND table_schema = DATABASE()
AND column_name = 'CloudLimitsArchived'
),
'ALTER TABLE Teams ADD COLUMN CloudLimitsArchived BOOLEAN NOT NULL DEFAULT FALSE;',
'SELECT 1'
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;

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

@@ -0,0 +1 @@
ALTER TABLE teams DROP COLUMN IF EXISTS CloudLimitsArchived;

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

@@ -0,0 +1 @@
ALTER TABLE teams ADD COLUMN IF NOT EXISTS CloudLimitsArchived bool NOT NULL DEFAULT FALSE;

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

@@ -24,32 +24,34 @@ const (
) )
type Team struct { type Team struct {
Id string `json:"id"` Id string `json:"id"`
CreateAt int64 `json:"create_at"` CreateAt int64 `json:"create_at"`
UpdateAt int64 `json:"update_at"` UpdateAt int64 `json:"update_at"`
DeleteAt int64 `json:"delete_at"` DeleteAt int64 `json:"delete_at"`
DisplayName string `json:"display_name"` DisplayName string `json:"display_name"`
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Email string `json:"email"` Email string `json:"email"`
Type string `json:"type"` Type string `json:"type"`
CompanyName string `json:"company_name"` CompanyName string `json:"company_name"`
AllowedDomains string `json:"allowed_domains"` AllowedDomains string `json:"allowed_domains"`
InviteId string `json:"invite_id"` InviteId string `json:"invite_id"`
AllowOpenInvite bool `json:"allow_open_invite"` AllowOpenInvite bool `json:"allow_open_invite"`
LastTeamIconUpdate int64 `json:"last_team_icon_update,omitempty"` LastTeamIconUpdate int64 `json:"last_team_icon_update,omitempty"`
SchemeId *string `json:"scheme_id"` SchemeId *string `json:"scheme_id"`
GroupConstrained *bool `json:"group_constrained"` GroupConstrained *bool `json:"group_constrained"`
PolicyID *string `json:"policy_id"` PolicyID *string `json:"policy_id"`
CloudLimitsArchived bool `json:"cloud_limits_archived"`
} }
type TeamPatch struct { type TeamPatch struct {
DisplayName *string `json:"display_name"` DisplayName *string `json:"display_name"`
Description *string `json:"description"` Description *string `json:"description"`
CompanyName *string `json:"company_name"` CompanyName *string `json:"company_name"`
AllowedDomains *string `json:"allowed_domains"` AllowedDomains *string `json:"allowed_domains"`
AllowOpenInvite *bool `json:"allow_open_invite"` AllowOpenInvite *bool `json:"allow_open_invite"`
GroupConstrained *bool `json:"group_constrained"` GroupConstrained *bool `json:"group_constrained"`
CloudLimitsArchived *bool `json:"cloud_limits_archived"`
} }
type TeamForExport struct { type TeamForExport struct {
@@ -246,6 +248,10 @@ func (o *Team) Patch(patch *TeamPatch) {
if patch.GroupConstrained != nil { if patch.GroupConstrained != nil {
o.GroupConstrained = patch.GroupConstrained o.GroupConstrained = patch.GroupConstrained
} }
if patch.CloudLimitsArchived != nil {
o.CloudLimitsArchived = *patch.CloudLimitsArchived
}
} }
func (o *Team) IsGroupConstrained() bool { func (o *Team) IsGroupConstrained() bool {

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

@@ -227,10 +227,10 @@ func (s SqlTeamStore) Save(team *model.Team) (*model.Team, error) {
if _, err := s.GetMasterX().NamedExec(`INSERT INTO Teams if _, err := s.GetMasterX().NamedExec(`INSERT INTO Teams
(Id, CreateAt, UpdateAt, DeleteAt, DisplayName, Name, Description, Email, Type, CompanyName, AllowedDomains, (Id, CreateAt, UpdateAt, DeleteAt, DisplayName, Name, Description, Email, Type, CompanyName, AllowedDomains,
InviteId, AllowOpenInvite, LastTeamIconUpdate, SchemeId, GroupConstrained) InviteId, AllowOpenInvite, LastTeamIconUpdate, SchemeId, GroupConstrained, CloudLimitsArchived)
VALUES VALUES
(:Id, :CreateAt, :UpdateAt, :DeleteAt, :DisplayName, :Name, :Description, :Email, :Type, :CompanyName, :AllowedDomains, (:Id, :CreateAt, :UpdateAt, :DeleteAt, :DisplayName, :Name, :Description, :Email, :Type, :CompanyName, :AllowedDomains,
:InviteId, :AllowOpenInvite, :LastTeamIconUpdate, :SchemeId, :GroupConstrained)`, team); err != nil { :InviteId, :AllowOpenInvite, :LastTeamIconUpdate, :SchemeId, :GroupConstrained, :CloudLimitsArchived)`, team); err != nil {
if IsUniqueConstraintError(err, []string{"Name", "teams_name_key"}) { if IsUniqueConstraintError(err, []string{"Name", "teams_name_key"}) {
return nil, store.NewErrInvalidInput("Team", "id", team.Id) return nil, store.NewErrInvalidInput("Team", "id", team.Id)
} }
@@ -268,7 +268,7 @@ func (s SqlTeamStore) Update(team *model.Team) (*model.Team, error) {
SET CreateAt=:CreateAt, UpdateAt=:UpdateAt, DeleteAt=:DeleteAt, DisplayName=:DisplayName, Name=:Name, SET CreateAt=:CreateAt, UpdateAt=:UpdateAt, DeleteAt=:DeleteAt, DisplayName=:DisplayName, Name=:Name,
Description=:Description, Email=:Email, Type=:Type, CompanyName=:CompanyName, AllowedDomains=:AllowedDomains, Description=:Description, Email=:Email, Type=:Type, CompanyName=:CompanyName, AllowedDomains=:AllowedDomains,
InviteId=:InviteId, AllowOpenInvite=:AllowOpenInvite, LastTeamIconUpdate=:LastTeamIconUpdate, InviteId=:InviteId, AllowOpenInvite=:AllowOpenInvite, LastTeamIconUpdate=:LastTeamIconUpdate,
SchemeId=:SchemeId, GroupConstrained=:GroupConstrained SchemeId=:SchemeId, GroupConstrained=:GroupConstrained, CloudLimitsArchived=:CloudLimitsArchived
WHERE Id=:Id`, team) WHERE Id=:Id`, team)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to update Team with id=%s", team.Id) return nil, errors.Wrapf(err, "failed to update Team with id=%s", team.Id)