summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Goldberg <george@gberg.me>2018-05-17 16:28:14 +0100
committerGitHub <noreply@github.com>2018-05-17 16:28:14 +0100
commita09dc68e1d99394f5d636284e0580dd17b2773b3 (patch)
tree83292b4af174445cde44309928d2ebf90d184910
parentd61f13d9b47efbbfb220b1ea33623372c4f6d1ae (diff)
downloadchat-a09dc68e1d99394f5d636284e0580dd17b2773b3.tar.gz
chat-a09dc68e1d99394f5d636284e0580dd17b2773b3.tar.bz2
chat-a09dc68e1d99394f5d636284e0580dd17b2773b3.zip
MM-10235: Make permissions reset CLI shcemes-aware. (#8773)
* MM-10235: Make permissions reset CLI shcemes-aware. * Add i18n strings.
-rw-r--r--app/permissions.go15
-rw-r--r--i18n/en.json12
-rw-r--r--store/layered_store.go6
-rw-r--r--store/layered_store_supplier.go1
-rw-r--r--store/local_cache_supplier_schemes.go6
-rw-r--r--store/redis_supplier_schemes.go5
-rw-r--r--store/sqlstore/channel_store.go8
-rw-r--r--store/sqlstore/scheme_supplier.go10
-rw-r--r--store/sqlstore/team_store.go8
-rw-r--r--store/store.go3
-rw-r--r--store/storetest/channel_store.go41
-rw-r--r--store/storetest/mocks/ChannelStore.go16
-rw-r--r--store/storetest/mocks/LayeredStoreDatabaseLayer.go23
-rw-r--r--store/storetest/mocks/LayeredStoreSupplier.go23
-rw-r--r--store/storetest/mocks/SchemeStore.go16
-rw-r--r--store/storetest/mocks/TeamStore.go16
-rw-r--r--store/storetest/scheme_store.go31
-rw-r--r--store/storetest/team_store.go41
18 files changed, 281 insertions, 0 deletions
diff --git a/app/permissions.go b/app/permissions.go
index be975e03d..75aa2ecf9 100644
--- a/app/permissions.go
+++ b/app/permissions.go
@@ -8,6 +8,21 @@ import (
)
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.
if result := <-a.Srv.Store.Role().PermanentDeleteAll(); result.Err != nil {
return result.Err
diff --git a/i18n/en.json b/i18n/en.json
index 5dc05eba7..8d2c90db0 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -276,6 +276,18 @@
"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",
"translation": "Must use createDirectChannel API service for direct message channel creation"
},
diff --git a/store/layered_store.go b/store/layered_store.go
index cbabe9d22..69513febf 100644
--- a/store/layered_store.go
+++ b/store/layered_store.go
@@ -298,3 +298,9 @@ func (s *LayeredSchemeStore) GetAllPage(scope string, offset int, limit int) Sto
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)
+ })
+}
diff --git a/store/layered_store_supplier.go b/store/layered_store_supplier.go
index 4f57004bb..6bf4a0310 100644
--- a/store/layered_store_supplier.go
+++ b/store/layered_store_supplier.go
@@ -43,4 +43,5 @@ type LayeredStoreSupplier interface {
SchemeGet(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
+ SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult
}
diff --git a/store/local_cache_supplier_schemes.go b/store/local_cache_supplier_schemes.go
index 809c60510..b6cde0fc4 100644
--- a/store/local_cache_supplier_schemes.go
+++ b/store/local_cache_supplier_schemes.go
@@ -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 {
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...)
+}
diff --git a/store/redis_supplier_schemes.go b/store/redis_supplier_schemes.go
index 3bd747044..1af9dafde 100644
--- a/store/redis_supplier_schemes.go
+++ b/store/redis_supplier_schemes.go
@@ -28,3 +28,8 @@ func (s *RedisSupplier) SchemeGetAllPage(ctx context.Context, scope string, offs
// TODO: Redis caching.
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...)
+}
diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go
index 4948d0995..5f336d904 100644
--- a/store/sqlstore/channel_store.go
+++ b/store/sqlstore/channel_store.go
@@ -1772,3 +1772,11 @@ func (s SqlChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId
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)
+ }
+ })
+}
diff --git a/store/sqlstore/scheme_supplier.go b/store/sqlstore/scheme_supplier.go
index 233d2f660..e15bb3629 100644
--- a/store/sqlstore/scheme_supplier.go
+++ b/store/sqlstore/scheme_supplier.go
@@ -282,3 +282,13 @@ func (s *SqlSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset
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
+}
diff --git a/store/sqlstore/team_store.go b/store/sqlstore/team_store.go
index ea5f7fd1f..f8d76bba1 100644
--- a/store/sqlstore/team_store.go
+++ b/store/sqlstore/team_store.go
@@ -794,3 +794,11 @@ func (s SqlTeamStore) MigrateTeamMembers(fromTeamId string, fromUserId string) s
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)
+ }
+ })
+}
diff --git a/store/store.go b/store/store.go
index bf2ac42f5..bfc0ab845 100644
--- a/store/store.go
+++ b/store/store.go
@@ -106,6 +106,7 @@ type TeamStore interface {
UpdateLastTeamIconUpdate(teamId string, curTime int64) StoreChannel
GetTeamsByScheme(schemeId string, offset int, limit int) StoreChannel
MigrateTeamMembers(fromTeamId string, fromUserId string) StoreChannel
+ ResetAllTeamSchemes() StoreChannel
}
type ChannelStore interface {
@@ -165,6 +166,7 @@ type ChannelStore interface {
ClearCaches()
GetChannelsByScheme(schemeId string, offset int, limit int) StoreChannel
MigrateChannelMembers(fromChannelId string, fromUserId string) StoreChannel
+ ResetAllChannelSchemes() StoreChannel
}
type ChannelMemberHistoryStore interface {
@@ -489,4 +491,5 @@ type SchemeStore interface {
Get(schemeId string) StoreChannel
GetAllPage(scope string, offset int, limit int) StoreChannel
Delete(schemeId string) StoreChannel
+ PermanentDeleteAll() StoreChannel
}
diff --git a/store/storetest/channel_store.go b/store/storetest/channel_store.go
index 6e0d30a2d..21db7eb91 100644
--- a/store/storetest/channel_store.go
+++ b/store/storetest/channel_store.go
@@ -54,6 +54,7 @@ func TestChannelStore(t *testing.T, ss store.Store) {
t.Run("MaxChannelsPerTeam", func(t *testing.T) { testChannelStoreMaxChannelsPerTeam(t, ss) })
t.Run("GetChannelsByScheme", func(t *testing.T) { testChannelStoreGetChannelsByScheme(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.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)
+}
diff --git a/store/storetest/mocks/ChannelStore.go b/store/storetest/mocks/ChannelStore.go
index 8858e3d3b..10ac908e4 100644
--- a/store/storetest/mocks/ChannelStore.go
+++ b/store/storetest/mocks/ChannelStore.go
@@ -679,6 +679,22 @@ func (_m *ChannelStore) RemoveMember(channelId string, userId string) store.Stor
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
func (_m *ChannelStore) Restore(channelId string, time int64) store.StoreChannel {
ret := _m.Called(channelId, time)
diff --git a/store/storetest/mocks/LayeredStoreDatabaseLayer.go b/store/storetest/mocks/LayeredStoreDatabaseLayer.go
index e6b8bafb1..c5b821b05 100644
--- a/store/storetest/mocks/LayeredStoreDatabaseLayer.go
+++ b/store/storetest/mocks/LayeredStoreDatabaseLayer.go
@@ -655,6 +655,29 @@ func (_m *LayeredStoreDatabaseLayer) SchemeGetAllPage(ctx context.Context, scope
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
func (_m *LayeredStoreDatabaseLayer) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
diff --git a/store/storetest/mocks/LayeredStoreSupplier.go b/store/storetest/mocks/LayeredStoreSupplier.go
index ef6fd99e2..37a01df14 100644
--- a/store/storetest/mocks/LayeredStoreSupplier.go
+++ b/store/storetest/mocks/LayeredStoreSupplier.go
@@ -352,6 +352,29 @@ func (_m *LayeredStoreSupplier) SchemeGetAllPage(ctx context.Context, scope stri
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
func (_m *LayeredStoreSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
diff --git a/store/storetest/mocks/SchemeStore.go b/store/storetest/mocks/SchemeStore.go
index 2868521b3..ffb10f931 100644
--- a/store/storetest/mocks/SchemeStore.go
+++ b/store/storetest/mocks/SchemeStore.go
@@ -61,6 +61,22 @@ func (_m *SchemeStore) GetAllPage(scope string, offset int, limit int) store.Sto
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
func (_m *SchemeStore) Save(scheme *model.Scheme) store.StoreChannel {
ret := _m.Called(scheme)
diff --git a/store/storetest/mocks/TeamStore.go b/store/storetest/mocks/TeamStore.go
index 93cb84caf..ef5529a1f 100644
--- a/store/storetest/mocks/TeamStore.go
+++ b/store/storetest/mocks/TeamStore.go
@@ -381,6 +381,22 @@ func (_m *TeamStore) RemoveMember(teamId string, userId string) store.StoreChann
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
func (_m *TeamStore) Save(team *model.Team) store.StoreChannel {
ret := _m.Called(team)
diff --git a/store/storetest/scheme_store.go b/store/storetest/scheme_store.go
index 49bc92bb6..636000953 100644
--- a/store/storetest/scheme_store.go
+++ b/store/storetest/scheme_store.go
@@ -19,6 +19,7 @@ func TestSchemeStore(t *testing.T, ss store.Store) {
t.Run("Get", func(t *testing.T) { testSchemeStoreGet(t, ss) })
t.Run("GetAllPage", func(t *testing.T) { testSchemeStoreGetAllPage(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) {
@@ -372,3 +373,33 @@ func testSchemeStoreDelete(t *testing.T, ss store.Store) {
c6 := cres6.Data.(*model.Channel)
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)
+}
diff --git a/store/storetest/team_store.go b/store/storetest/team_store.go
index 726c17a99..996f8fd8f 100644
--- a/store/storetest/team_store.go
+++ b/store/storetest/team_store.go
@@ -41,6 +41,7 @@ func TestTeamStore(t *testing.T, ss store.Store) {
t.Run("UpdateLastTeamIconUpdate", func(t *testing.T) { testUpdateLastTeamIconUpdate(t, ss) })
t.Run("GetTeamsByScheme", func(t *testing.T) { testGetTeamsByScheme(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) {
@@ -1169,3 +1170,43 @@ func testTeamStoreMigrateTeamMembers(t *testing.T, ss store.Store) {
assert.False(t, tm3b.SchemeUser)
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)
+}