MM-10235: Make permissions reset CLI shcemes-aware. (#8773)

* MM-10235: Make permissions reset CLI shcemes-aware.

* Add i18n strings.
Этот коммит содержится в:
George Goldberg
2018-05-17 16:28:14 +01:00
коммит произвёл GitHub
родитель d61f13d9b4
Коммит a09dc68e1d
18 изменённых файлов: 281 добавлений и 0 удалений

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

@@ -8,6 +8,21 @@ import (
) )
func (a *App) ResetPermissionsSystem() *model.AppError { func (a *App) ResetPermissionsSystem() *model.AppError {
// Reset all Teams to not have a scheme.
if result := <-a.Srv.Store.Team().ResetAllTeamSchemes(); result.Err != nil {
return result.Err
}
// Reset all Channels to not have a scheme.
if result := <-a.Srv.Store.Channel().ResetAllChannelSchemes(); result.Err != nil {
return result.Err
}
// Purge all schemes from the database.
if result := <-a.Srv.Store.Scheme().PermanentDeleteAll(); result.Err != nil {
return result.Err
}
// Purge all roles from the database. // Purge all roles from the database.
if result := <-a.Srv.Store.Role().PermanentDeleteAll(); result.Err != nil { if result := <-a.Srv.Store.Role().PermanentDeleteAll(); result.Err != nil {
return result.Err return result.Err

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

@@ -275,6 +275,18 @@
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "The channel requested to convert is already a private channel."
}, },
{
"id": "store.sql_channel.reset_all_channel_schemes.app_error",
"translation": "We could not reset the channel schemes"
},
{
"id": "store.sql_scheme.permanent_delete_all.app_error",
"translation": "We could not permanently delete the schemes"
},
{
"id": "store.sql_team.reset_all_team_schemes.app_error",
"translation": "We could not reset the team schemes"
},
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
"translation": "Must use createDirectChannel API service for direct message channel creation" "translation": "Must use createDirectChannel API service for direct message channel creation"

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

@@ -298,3 +298,9 @@ func (s *LayeredSchemeStore) GetAllPage(scope string, offset int, limit int) Sto
return supplier.SchemeGetAllPage(s.TmpContext, scope, offset, limit) return supplier.SchemeGetAllPage(s.TmpContext, scope, offset, limit)
}) })
} }
func (s *LayeredSchemeStore) PermanentDeleteAll() StoreChannel {
return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult {
return supplier.SchemePermanentDeleteAll(s.TmpContext)
})
}

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

@@ -43,4 +43,5 @@ type LayeredStoreSupplier interface {
SchemeGet(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeGet(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult
SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult
SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult
SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult
} }

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

@@ -46,3 +46,9 @@ func (s *LocalCacheSupplier) SchemeDelete(ctx context.Context, schemeId string,
func (s *LocalCacheSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { func (s *LocalCacheSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult {
return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...) return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...)
} }
func (s *LocalCacheSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult {
defer s.doClearCacheCluster(s.schemeCache)
return s.Next().SchemePermanentDeleteAll(ctx, hints...)
}

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

@@ -28,3 +28,8 @@ func (s *RedisSupplier) SchemeGetAllPage(ctx context.Context, scope string, offs
// TODO: Redis caching. // TODO: Redis caching.
return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...) return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...)
} }
func (s *RedisSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult {
// TODO: Redis caching.
return s.Next().SchemePermanentDeleteAll(ctx, hints...)
}

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

@@ -1772,3 +1772,11 @@ func (s SqlChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId
result.Data = data result.Data = data
}) })
} }
func (s SqlChannelStore) ResetAllChannelSchemes() store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
if _, err := s.GetMaster().Exec("UPDATE Channels SET SchemeId=''"); err != nil {
result.Err = model.NewAppError("SqlChannelStore.ResetAllChannelSchemes", "store.sql_channel.reset_all_channel_schemes.app_error", nil, err.Error(), http.StatusInternalServerError)
}
})
}

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

@@ -282,3 +282,13 @@ func (s *SqlSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset
return result return result
} }
func (s *SqlSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
result := store.NewSupplierResult()
if _, err := s.GetMaster().Exec("DELETE from Schemes"); err != nil {
result.Err = model.NewAppError("SqlSchemeStore.PermanentDeleteAll", "store.sql_scheme.permanent_delete_all.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return result
}

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

@@ -794,3 +794,11 @@ func (s SqlTeamStore) MigrateTeamMembers(fromTeamId string, fromUserId string) s
result.Data = data result.Data = data
}) })
} }
func (s SqlTeamStore) ResetAllTeamSchemes() store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
if _, err := s.GetMaster().Exec("UPDATE Teams SET SchemeId=''"); err != nil {
result.Err = model.NewAppError("SqlTeamStore.ResetAllTeamSchemes", "store.sql_team.reset_all_team_schemes.app_error", nil, err.Error(), http.StatusInternalServerError)
}
})
}

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

@@ -106,6 +106,7 @@ type TeamStore interface {
UpdateLastTeamIconUpdate(teamId string, curTime int64) StoreChannel UpdateLastTeamIconUpdate(teamId string, curTime int64) StoreChannel
GetTeamsByScheme(schemeId string, offset int, limit int) StoreChannel GetTeamsByScheme(schemeId string, offset int, limit int) StoreChannel
MigrateTeamMembers(fromTeamId string, fromUserId string) StoreChannel MigrateTeamMembers(fromTeamId string, fromUserId string) StoreChannel
ResetAllTeamSchemes() StoreChannel
} }
type ChannelStore interface { type ChannelStore interface {
@@ -165,6 +166,7 @@ type ChannelStore interface {
ClearCaches() ClearCaches()
GetChannelsByScheme(schemeId string, offset int, limit int) StoreChannel GetChannelsByScheme(schemeId string, offset int, limit int) StoreChannel
MigrateChannelMembers(fromChannelId string, fromUserId string) StoreChannel MigrateChannelMembers(fromChannelId string, fromUserId string) StoreChannel
ResetAllChannelSchemes() StoreChannel
} }
type ChannelMemberHistoryStore interface { type ChannelMemberHistoryStore interface {
@@ -489,4 +491,5 @@ type SchemeStore interface {
Get(schemeId string) StoreChannel Get(schemeId string) StoreChannel
GetAllPage(scope string, offset int, limit int) StoreChannel GetAllPage(scope string, offset int, limit int) StoreChannel
Delete(schemeId string) StoreChannel Delete(schemeId string) StoreChannel
PermanentDeleteAll() StoreChannel
} }

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

@@ -54,6 +54,7 @@ func TestChannelStore(t *testing.T, ss store.Store) {
t.Run("MaxChannelsPerTeam", func(t *testing.T) { testChannelStoreMaxChannelsPerTeam(t, ss) }) t.Run("MaxChannelsPerTeam", func(t *testing.T) { testChannelStoreMaxChannelsPerTeam(t, ss) })
t.Run("GetChannelsByScheme", func(t *testing.T) { testChannelStoreGetChannelsByScheme(t, ss) }) t.Run("GetChannelsByScheme", func(t *testing.T) { testChannelStoreGetChannelsByScheme(t, ss) })
t.Run("MigrateChannelMembers", func(t *testing.T) { testChannelStoreMigrateChannelMembers(t, ss) }) t.Run("MigrateChannelMembers", func(t *testing.T) { testChannelStoreMigrateChannelMembers(t, ss) })
t.Run("ResetAllChannelSchemes", func(t *testing.T) { testResetAllChannelSchemes(t, ss) })
} }
@@ -2296,3 +2297,43 @@ func testChannelStoreMigrateChannelMembers(t *testing.T, ss store.Store) {
assert.False(t, cm3b.SchemeUser) assert.False(t, cm3b.SchemeUser)
assert.False(t, cm3b.SchemeAdmin) assert.False(t, cm3b.SchemeAdmin)
} }
func testResetAllChannelSchemes(t *testing.T, ss store.Store) {
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_CHANNEL,
}
s1 = (<-ss.Scheme().Save(s1)).Data.(*model.Scheme)
c1 := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Name",
Name: model.NewId(),
Type: model.CHANNEL_OPEN,
SchemeId: &s1.Id,
}
c2 := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Name",
Name: model.NewId(),
Type: model.CHANNEL_OPEN,
SchemeId: &s1.Id,
}
c1 = (<-ss.Channel().Save(c1, 100)).Data.(*model.Channel)
c2 = (<-ss.Channel().Save(c2, 100)).Data.(*model.Channel)
assert.Equal(t, s1.Id, *c1.SchemeId)
assert.Equal(t, s1.Id, *c2.SchemeId)
res := <-ss.Channel().ResetAllChannelSchemes()
assert.Nil(t, res.Err)
c1 = (<-ss.Channel().Get(c1.Id, true)).Data.(*model.Channel)
c2 = (<-ss.Channel().Get(c2.Id, true)).Data.(*model.Channel)
assert.Equal(t, "", *c1.SchemeId)
assert.Equal(t, "", *c2.SchemeId)
}

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

@@ -679,6 +679,22 @@ func (_m *ChannelStore) RemoveMember(channelId string, userId string) store.Stor
return r0 return r0
} }
// ResetAllChannelSchemes provides a mock function with given fields:
func (_m *ChannelStore) ResetAllChannelSchemes() store.StoreChannel {
ret := _m.Called()
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func() store.StoreChannel); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// Restore provides a mock function with given fields: channelId, time // Restore provides a mock function with given fields: channelId, time
func (_m *ChannelStore) Restore(channelId string, time int64) store.StoreChannel { func (_m *ChannelStore) Restore(channelId string, time int64) store.StoreChannel {
ret := _m.Called(channelId, time) ret := _m.Called(channelId, time)

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

@@ -655,6 +655,29 @@ func (_m *LayeredStoreDatabaseLayer) SchemeGetAllPage(ctx context.Context, scope
return r0 return r0
} }
// SchemePermanentDeleteAll provides a mock function with given fields: ctx, hints
func (_m *LayeredStoreDatabaseLayer) SchemePermanentDeleteAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// SchemeSave provides a mock function with given fields: ctx, scheme, hints // SchemeSave provides a mock function with given fields: ctx, scheme, hints
func (_m *LayeredStoreDatabaseLayer) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { func (_m *LayeredStoreDatabaseLayer) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints)) _va := make([]interface{}, len(hints))

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

@@ -352,6 +352,29 @@ func (_m *LayeredStoreSupplier) SchemeGetAllPage(ctx context.Context, scope stri
return r0 return r0
} }
// SchemePermanentDeleteAll provides a mock function with given fields: ctx, hints
func (_m *LayeredStoreSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// SchemeSave provides a mock function with given fields: ctx, scheme, hints // SchemeSave provides a mock function with given fields: ctx, scheme, hints
func (_m *LayeredStoreSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { func (_m *LayeredStoreSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints)) _va := make([]interface{}, len(hints))

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

@@ -61,6 +61,22 @@ func (_m *SchemeStore) GetAllPage(scope string, offset int, limit int) store.Sto
return r0 return r0
} }
// PermanentDeleteAll provides a mock function with given fields:
func (_m *SchemeStore) PermanentDeleteAll() store.StoreChannel {
ret := _m.Called()
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func() store.StoreChannel); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// Save provides a mock function with given fields: scheme // Save provides a mock function with given fields: scheme
func (_m *SchemeStore) Save(scheme *model.Scheme) store.StoreChannel { func (_m *SchemeStore) Save(scheme *model.Scheme) store.StoreChannel {
ret := _m.Called(scheme) ret := _m.Called(scheme)

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

@@ -381,6 +381,22 @@ func (_m *TeamStore) RemoveMember(teamId string, userId string) store.StoreChann
return r0 return r0
} }
// ResetAllTeamSchemes provides a mock function with given fields:
func (_m *TeamStore) ResetAllTeamSchemes() store.StoreChannel {
ret := _m.Called()
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func() store.StoreChannel); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// Save provides a mock function with given fields: team // Save provides a mock function with given fields: team
func (_m *TeamStore) Save(team *model.Team) store.StoreChannel { func (_m *TeamStore) Save(team *model.Team) store.StoreChannel {
ret := _m.Called(team) ret := _m.Called(team)

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

@@ -19,6 +19,7 @@ func TestSchemeStore(t *testing.T, ss store.Store) {
t.Run("Get", func(t *testing.T) { testSchemeStoreGet(t, ss) }) t.Run("Get", func(t *testing.T) { testSchemeStoreGet(t, ss) })
t.Run("GetAllPage", func(t *testing.T) { testSchemeStoreGetAllPage(t, ss) }) t.Run("GetAllPage", func(t *testing.T) { testSchemeStoreGetAllPage(t, ss) })
t.Run("Delete", func(t *testing.T) { testSchemeStoreDelete(t, ss) }) t.Run("Delete", func(t *testing.T) { testSchemeStoreDelete(t, ss) })
t.Run("PermanentDeleteAll", func(t *testing.T) { testSchemeStorePermanentDeleteAll(t, ss) })
} }
func createDefaultRoles(t *testing.T, ss store.Store) { func createDefaultRoles(t *testing.T, ss store.Store) {
@@ -372,3 +373,33 @@ func testSchemeStoreDelete(t *testing.T, ss store.Store) {
c6 := cres6.Data.(*model.Channel) c6 := cres6.Data.(*model.Channel)
assert.Equal(t, "", *c6.SchemeId) assert.Equal(t, "", *c6.SchemeId)
} }
func testSchemeStorePermanentDeleteAll(t *testing.T, ss store.Store) {
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
s2 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_CHANNEL,
}
s1 = (<-ss.Scheme().Save(s1)).Data.(*model.Scheme)
s2 = (<-ss.Scheme().Save(s2)).Data.(*model.Scheme)
res := <-ss.Scheme().PermanentDeleteAll()
assert.Nil(t, res.Err)
res1 := <-ss.Scheme().Get(s1.Id)
assert.NotNil(t, res1.Err)
res2 := <-ss.Scheme().Get(s2.Id)
assert.NotNil(t, res2.Err)
res3 := <-ss.Scheme().GetAllPage("", 0, 100000)
assert.Nil(t, res3.Err)
assert.Len(t, res3.Data.([]*model.Scheme), 0)
}

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

@@ -41,6 +41,7 @@ func TestTeamStore(t *testing.T, ss store.Store) {
t.Run("UpdateLastTeamIconUpdate", func(t *testing.T) { testUpdateLastTeamIconUpdate(t, ss) }) t.Run("UpdateLastTeamIconUpdate", func(t *testing.T) { testUpdateLastTeamIconUpdate(t, ss) })
t.Run("GetTeamsByScheme", func(t *testing.T) { testGetTeamsByScheme(t, ss) }) t.Run("GetTeamsByScheme", func(t *testing.T) { testGetTeamsByScheme(t, ss) })
t.Run("MigrateTeamMembers", func(t *testing.T) { testTeamStoreMigrateTeamMembers(t, ss) }) t.Run("MigrateTeamMembers", func(t *testing.T) { testTeamStoreMigrateTeamMembers(t, ss) })
t.Run("ResetAllTeamSchemes", func(t *testing.T) { testResetAllTeamSchemes(t, ss) })
} }
func testTeamStoreSave(t *testing.T, ss store.Store) { func testTeamStoreSave(t *testing.T, ss store.Store) {
@@ -1169,3 +1170,43 @@ func testTeamStoreMigrateTeamMembers(t *testing.T, ss store.Store) {
assert.False(t, tm3b.SchemeUser) assert.False(t, tm3b.SchemeUser)
assert.False(t, tm3b.SchemeAdmin) assert.False(t, tm3b.SchemeAdmin)
} }
func testResetAllTeamSchemes(t *testing.T, ss store.Store) {
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
s1 = (<-ss.Scheme().Save(s1)).Data.(*model.Scheme)
t1 := &model.Team{
Name: model.NewId(),
DisplayName: model.NewId(),
Email: model.NewId() + "@nowhere.com",
Type: model.TEAM_OPEN,
SchemeId: &s1.Id,
}
t2 := &model.Team{
Name: model.NewId(),
DisplayName: model.NewId(),
Email: model.NewId() + "@nowhere.com",
Type: model.TEAM_OPEN,
SchemeId: &s1.Id,
}
t1 = (<-ss.Team().Save(t1)).Data.(*model.Team)
t2 = (<-ss.Team().Save(t2)).Data.(*model.Team)
assert.Equal(t, s1.Id, *t1.SchemeId)
assert.Equal(t, s1.Id, *t2.SchemeId)
res := <-ss.Team().ResetAllTeamSchemes()
assert.Nil(t, res.Err)
t1 = (<-ss.Team().Get(t1.Id)).Data.(*model.Team)
t2 = (<-ss.Team().Get(t2.Id)).Data.(*model.Team)
assert.Equal(t, "", *t1.SchemeId)
assert.Equal(t, "", *t2.SchemeId)
}