github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/store/sqlstore/role_store.go (about) 1 package sqlstore 2 3 import ( 4 "context" 5 "database/sql" 6 "fmt" 7 "strings" 8 9 sq "github.com/Masterminds/squirrel" 10 "github.com/mattermost/gorp" 11 "github.com/pkg/errors" 12 13 "github.com/masterhung0112/hk_server/v5/model" 14 "github.com/masterhung0112/hk_server/v5/store" 15 ) 16 17 type SqlRoleStore struct { 18 *SqlStore 19 } 20 21 type Role struct { 22 Id string 23 Name string 24 DisplayName string 25 Description string 26 CreateAt int64 27 UpdateAt int64 28 DeleteAt int64 29 Permissions string 30 SchemeManaged bool 31 BuiltIn bool 32 } 33 34 type channelRolesPermissions struct { 35 GuestRoleName string 36 UserRoleName string 37 AdminRoleName string 38 HigherScopedGuestPermissions string 39 HigherScopedUserPermissions string 40 HigherScopedAdminPermissions string 41 } 42 43 func NewRoleFromModel(role *model.Role) *Role { 44 permissionsMap := make(map[string]bool) 45 permissions := "" 46 47 for _, permission := range role.Permissions { 48 if !permissionsMap[permission] { 49 permissions += fmt.Sprintf(" %v", permission) 50 permissionsMap[permission] = true 51 } 52 } 53 54 return &Role{ 55 Id: role.Id, 56 Name: role.Name, 57 DisplayName: role.DisplayName, 58 Description: role.Description, 59 CreateAt: role.CreateAt, 60 UpdateAt: role.UpdateAt, 61 DeleteAt: role.DeleteAt, 62 Permissions: permissions, 63 SchemeManaged: role.SchemeManaged, 64 BuiltIn: role.BuiltIn, 65 } 66 } 67 68 func (role Role) ToModel() *model.Role { 69 return &model.Role{ 70 Id: role.Id, 71 Name: role.Name, 72 DisplayName: role.DisplayName, 73 Description: role.Description, 74 CreateAt: role.CreateAt, 75 UpdateAt: role.UpdateAt, 76 DeleteAt: role.DeleteAt, 77 Permissions: strings.Fields(role.Permissions), 78 SchemeManaged: role.SchemeManaged, 79 BuiltIn: role.BuiltIn, 80 } 81 } 82 83 func newSqlRoleStore(sqlStore *SqlStore) store.RoleStore { 84 s := &SqlRoleStore{sqlStore} 85 86 for _, db := range sqlStore.GetAllConns() { 87 table := db.AddTableWithName(Role{}, "Roles").SetKeys(false, "Id") 88 table.ColMap("Id").SetMaxSize(26) 89 table.ColMap("Name").SetMaxSize(64).SetUnique(true) 90 table.ColMap("DisplayName").SetMaxSize(128) 91 table.ColMap("Description").SetMaxSize(1024) 92 table.ColMap("Permissions").SetMaxSize(8192) 93 } 94 return s 95 } 96 97 func (s *SqlRoleStore) Save(role *model.Role) (*model.Role, error) { 98 // Check the role is valid before proceeding. 99 if !role.IsValidWithoutId() { 100 return nil, store.NewErrInvalidInput("Role", "<any>", fmt.Sprintf("%v", role)) 101 } 102 103 if role.Id == "" { 104 transaction, err := s.GetMaster().Begin() 105 if err != nil { 106 return nil, errors.Wrap(err, "begin_transaction") 107 } 108 defer finalizeTransaction(transaction) 109 createdRole, err := s.createRole(role, transaction) 110 if err != nil { 111 _ = transaction.Rollback() 112 return nil, errors.Wrap(err, "unable to create Role") 113 } else if err := transaction.Commit(); err != nil { 114 return nil, errors.Wrap(err, "commit_transaction") 115 } 116 return createdRole, nil 117 } 118 119 dbRole := NewRoleFromModel(role) 120 dbRole.UpdateAt = model.GetMillis() 121 if rowsChanged, err := s.GetMaster().Update(dbRole); err != nil { 122 return nil, errors.Wrap(err, "failed to update Role") 123 } else if rowsChanged != 1 { 124 return nil, fmt.Errorf("invalid number of updated rows, expected 1 but got %d", rowsChanged) 125 } 126 127 return dbRole.ToModel(), nil 128 } 129 130 func (s *SqlRoleStore) createRole(role *model.Role, transaction *gorp.Transaction) (*model.Role, error) { 131 // Check the role is valid before proceeding. 132 if !role.IsValidWithoutId() { 133 return nil, store.NewErrInvalidInput("Role", "<any>", fmt.Sprintf("%v", role)) 134 } 135 136 dbRole := NewRoleFromModel(role) 137 138 dbRole.Id = model.NewId() 139 dbRole.CreateAt = model.GetMillis() 140 dbRole.UpdateAt = dbRole.CreateAt 141 142 if err := transaction.Insert(dbRole); err != nil { 143 return nil, errors.Wrap(err, "failed to save Role") 144 } 145 146 return dbRole.ToModel(), nil 147 } 148 149 func (s *SqlRoleStore) Get(roleId string) (*model.Role, error) { 150 var dbRole Role 151 152 if err := s.GetReplica().SelectOne(&dbRole, "SELECT * from Roles WHERE Id = :Id", map[string]interface{}{"Id": roleId}); err != nil { 153 if err == sql.ErrNoRows { 154 return nil, store.NewErrNotFound("Role", roleId) 155 } 156 return nil, errors.Wrap(err, "failed to get Role") 157 } 158 159 return dbRole.ToModel(), nil 160 } 161 162 func (s *SqlRoleStore) GetAll() ([]*model.Role, error) { 163 var dbRoles []Role 164 165 if _, err := s.GetReplica().Select(&dbRoles, "SELECT * from Roles", map[string]interface{}{}); err != nil { 166 return nil, errors.Wrap(err, "failed to find Roles") 167 } 168 169 var roles []*model.Role 170 for _, dbRole := range dbRoles { 171 roles = append(roles, dbRole.ToModel()) 172 } 173 return roles, nil 174 } 175 176 func (s *SqlRoleStore) GetByName(ctx context.Context, name string) (*model.Role, error) { 177 var dbRole Role 178 if err := s.DBFromContext(ctx).SelectOne(&dbRole, "SELECT * from Roles WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil { 179 if err == sql.ErrNoRows { 180 return nil, store.NewErrNotFound("Role", fmt.Sprintf("name=%s", name)) 181 } 182 return nil, errors.Wrapf(err, "failed to find Roles with name=%s", name) 183 } 184 185 return dbRole.ToModel(), nil 186 } 187 188 func (s *SqlRoleStore) GetByNames(names []string) ([]*model.Role, error) { 189 if len(names) == 0 { 190 return []*model.Role{}, nil 191 } 192 193 query := s.getQueryBuilder(). 194 Select("Id, Name, DisplayName, Description, CreateAt, UpdateAt, DeleteAt, Permissions, SchemeManaged, BuiltIn"). 195 From("Roles"). 196 Where(sq.Eq{"Name": names}) 197 queryString, args, err := query.ToSql() 198 if err != nil { 199 return nil, errors.Wrap(err, "role_tosql") 200 } 201 202 rows, err := s.GetReplica().Db.Query(queryString, args...) 203 if err != nil { 204 return nil, errors.Wrap(err, "failed to find Roles") 205 } 206 207 var roles []*model.Role 208 defer rows.Close() 209 for rows.Next() { 210 var role Role 211 err = rows.Scan( 212 &role.Id, &role.Name, &role.DisplayName, &role.Description, 213 &role.CreateAt, &role.UpdateAt, &role.DeleteAt, &role.Permissions, 214 &role.SchemeManaged, &role.BuiltIn) 215 if err != nil { 216 return nil, errors.Wrap(err, "failed to scan values") 217 } 218 roles = append(roles, role.ToModel()) 219 } 220 if err = rows.Err(); err != nil { 221 return nil, errors.Wrap(err, "unable to iterate over rows") 222 } 223 224 return roles, nil 225 } 226 227 func (s *SqlRoleStore) Delete(roleId string) (*model.Role, error) { 228 // Get the role. 229 var role *Role 230 if err := s.GetReplica().SelectOne(&role, "SELECT * from Roles WHERE Id = :Id", map[string]interface{}{"Id": roleId}); err != nil { 231 if err == sql.ErrNoRows { 232 return nil, store.NewErrNotFound("Role", roleId) 233 } 234 return nil, errors.Wrapf(err, "failed to get Role with id=%s", roleId) 235 } 236 237 time := model.GetMillis() 238 role.DeleteAt = time 239 role.UpdateAt = time 240 241 if rowsChanged, err := s.GetMaster().Update(role); err != nil { 242 return nil, errors.Wrap(err, "failed to update Role") 243 } else if rowsChanged != 1 { 244 return nil, errors.Wrapf(err, "invalid number of updated rows, expected 1 but got %d", rowsChanged) 245 } 246 return role.ToModel(), nil 247 } 248 249 func (s *SqlRoleStore) PermanentDeleteAll() error { 250 if _, err := s.GetMaster().Exec("DELETE FROM Roles"); err != nil { 251 return errors.Wrap(err, "failed to delete Roles") 252 } 253 254 return nil 255 } 256 257 func (s *SqlRoleStore) channelHigherScopedPermissionsQuery(roleNames []string) string { 258 sqlTmpl := ` 259 SELECT 260 '' AS GuestRoleName, 261 RoleSchemes.DefaultChannelUserRole AS UserRoleName, 262 RoleSchemes.DefaultChannelAdminRole AS AdminRoleName, 263 '' AS HigherScopedGuestPermissions, 264 UserRoles.Permissions AS HigherScopedUserPermissions, 265 AdminRoles.Permissions AS HigherScopedAdminPermissions 266 FROM 267 Schemes AS RoleSchemes 268 JOIN Channels ON Channels.SchemeId = RoleSchemes.Id 269 JOIN Teams ON Teams.Id = Channels.TeamId 270 JOIN Schemes ON Schemes.Id = Teams.SchemeId 271 RIGHT JOIN Roles AS UserRoles ON UserRoles.Name = Schemes.DefaultChannelUserRole 272 RIGHT JOIN Roles AS AdminRoles ON AdminRoles.Name = Schemes.DefaultChannelAdminRole 273 WHERE 274 RoleSchemes.DefaultChannelUserRole IN ('%[1]s') 275 OR RoleSchemes.DefaultChannelAdminRole IN ('%[1]s') 276 277 UNION 278 279 SELECT 280 RoleSchemes.DefaultChannelGuestRole AS GuestRoleName, 281 '' AS UserRoleName, 282 '' AS AdminRoleName, 283 GuestRoles.Permissions AS HigherScopedGuestPermissions, 284 '' AS HigherScopedUserPermissions, 285 '' AS HigherScopedAdminPermissions 286 FROM 287 Schemes AS RoleSchemes 288 JOIN Channels ON Channels.SchemeId = RoleSchemes.Id 289 JOIN Teams ON Teams.Id = Channels.TeamId 290 JOIN Schemes ON Schemes.Id = Teams.SchemeId 291 RIGHT JOIN Roles AS GuestRoles ON GuestRoles.Name = Schemes.DefaultChannelGuestRole 292 WHERE 293 RoleSchemes.DefaultChannelGuestRole IN ('%[1]s') 294 295 UNION 296 297 SELECT 298 Schemes.DefaultChannelGuestRole AS GuestRoleName, 299 Schemes.DefaultChannelUserRole AS UserRoleName, 300 Schemes.DefaultChannelAdminRole AS AdminRoleName, 301 GuestRoles.Permissions AS HigherScopedGuestPermissions, 302 UserRoles.Permissions AS HigherScopedUserPermissions, 303 AdminRoles.Permissions AS HigherScopedAdminPermissions 304 FROM 305 Schemes 306 JOIN Channels ON Channels.SchemeId = Schemes.Id 307 JOIN Teams ON Teams.Id = Channels.TeamId 308 JOIN Roles AS GuestRoles ON GuestRoles.Name = '%[2]s' 309 JOIN Roles AS UserRoles ON UserRoles.Name = '%[3]s' 310 JOIN Roles AS AdminRoles ON AdminRoles.Name = '%[4]s' 311 WHERE 312 (Schemes.DefaultChannelGuestRole IN ('%[1]s') 313 OR Schemes.DefaultChannelUserRole IN ('%[1]s') 314 OR Schemes.DefaultChannelAdminRole IN ('%[1]s')) 315 AND (Teams.SchemeId = '' 316 OR Teams.SchemeId IS NULL) 317 ` 318 319 // The below three channel role names are referenced by their name value because there is no system scheme 320 // record that ships with Mattermost, otherwise the system scheme would be referenced by name and the channel 321 // roles would be referenced by their column names. 322 return fmt.Sprintf( 323 sqlTmpl, 324 strings.Join(roleNames, "', '"), 325 model.CHANNEL_GUEST_ROLE_ID, 326 model.CHANNEL_USER_ROLE_ID, 327 model.CHANNEL_ADMIN_ROLE_ID, 328 ) 329 } 330 331 func (s *SqlRoleStore) ChannelHigherScopedPermissions(roleNames []string) (map[string]*model.RolePermissions, error) { 332 query := s.channelHigherScopedPermissionsQuery(roleNames) 333 334 var rolesPermissions []*channelRolesPermissions 335 if _, err := s.GetReplica().Select(&rolesPermissions, query); err != nil { 336 return nil, errors.Wrap(err, "failed to find RolePermissions") 337 } 338 339 roleNameHigherScopedPermissions := map[string]*model.RolePermissions{} 340 341 for _, rp := range rolesPermissions { 342 roleNameHigherScopedPermissions[rp.GuestRoleName] = &model.RolePermissions{RoleID: model.CHANNEL_GUEST_ROLE_ID, Permissions: strings.Split(rp.HigherScopedGuestPermissions, " ")} 343 roleNameHigherScopedPermissions[rp.UserRoleName] = &model.RolePermissions{RoleID: model.CHANNEL_USER_ROLE_ID, Permissions: strings.Split(rp.HigherScopedUserPermissions, " ")} 344 roleNameHigherScopedPermissions[rp.AdminRoleName] = &model.RolePermissions{RoleID: model.CHANNEL_ADMIN_ROLE_ID, Permissions: strings.Split(rp.HigherScopedAdminPermissions, " ")} 345 } 346 347 return roleNameHigherScopedPermissions, nil 348 } 349 350 func (s *SqlRoleStore) AllChannelSchemeRoles() ([]*model.Role, error) { 351 query := s.getQueryBuilder(). 352 Select("Roles.*"). 353 From("Schemes"). 354 Join("Roles ON Schemes.DefaultChannelGuestRole = Roles.Name OR Schemes.DefaultChannelUserRole = Roles.Name OR Schemes.DefaultChannelAdminRole = Roles.Name"). 355 Where(sq.Eq{"Schemes.Scope": model.SCHEME_SCOPE_CHANNEL}). 356 Where(sq.Eq{"Roles.DeleteAt": 0}). 357 Where(sq.Eq{"Schemes.DeleteAt": 0}) 358 359 queryString, args, err := query.ToSql() 360 if err != nil { 361 return nil, errors.Wrap(err, "role_tosql") 362 } 363 364 var dbRoles []*Role 365 if _, err = s.GetReplica().Select(&dbRoles, queryString, args...); err != nil { 366 return nil, errors.Wrap(err, "failed to find Roles") 367 } 368 369 var roles []*model.Role 370 for _, dbRole := range dbRoles { 371 roles = append(roles, dbRole.ToModel()) 372 } 373 374 return roles, nil 375 } 376 377 // ChannelRolesUnderTeamRole finds all of the channel-scheme roles under the team of the given team-scheme role. 378 func (s *SqlRoleStore) ChannelRolesUnderTeamRole(roleName string) ([]*model.Role, error) { 379 query := s.getQueryBuilder(). 380 Select("ChannelSchemeRoles.*"). 381 From("Roles AS HigherScopedRoles"). 382 Join("Schemes AS HigherScopedSchemes ON (HigherScopedRoles.Name = HigherScopedSchemes.DefaultChannelGuestRole OR HigherScopedRoles.Name = HigherScopedSchemes.DefaultChannelUserRole OR HigherScopedRoles.Name = HigherScopedSchemes.DefaultChannelAdminRole)"). 383 Join("Teams ON Teams.SchemeId = HigherScopedSchemes.Id"). 384 Join("Channels ON Channels.TeamId = Teams.Id"). 385 Join("Schemes AS ChannelSchemes ON Channels.SchemeId = ChannelSchemes.Id"). 386 Join("Roles AS ChannelSchemeRoles ON (ChannelSchemeRoles.Name = ChannelSchemes.DefaultChannelGuestRole OR ChannelSchemeRoles.Name = ChannelSchemes.DefaultChannelUserRole OR ChannelSchemeRoles.Name = ChannelSchemes.DefaultChannelAdminRole)"). 387 Where(sq.Eq{"HigherScopedSchemes.Scope": model.SCHEME_SCOPE_TEAM}). 388 Where(sq.Eq{"HigherScopedRoles.Name": roleName}). 389 Where(sq.Eq{"HigherScopedRoles.DeleteAt": 0}). 390 Where(sq.Eq{"HigherScopedSchemes.DeleteAt": 0}). 391 Where(sq.Eq{"Teams.DeleteAt": 0}). 392 Where(sq.Eq{"Channels.DeleteAt": 0}). 393 Where(sq.Eq{"ChannelSchemes.DeleteAt": 0}). 394 Where(sq.Eq{"ChannelSchemeRoles.DeleteAt": 0}) 395 396 queryString, args, err := query.ToSql() 397 if err != nil { 398 return nil, errors.Wrap(err, "role_tosql") 399 } 400 401 var dbRoles []*Role 402 if _, err = s.GetReplica().Select(&dbRoles, queryString, args...); err != nil { 403 return nil, errors.Wrap(err, "failed to find Roles") 404 } 405 406 var roles []*model.Role 407 for _, dbRole := range dbRoles { 408 roles = append(roles, dbRole.ToModel()) 409 } 410 411 return roles, nil 412 }