github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/role.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "errors" 8 "net/http" 9 "reflect" 10 "strings" 11 12 "github.com/mattermost/mattermost-server/v5/model" 13 "github.com/mattermost/mattermost-server/v5/store" 14 "github.com/mattermost/mattermost-server/v5/utils" 15 ) 16 17 func (a *App) GetRole(id string) (*model.Role, *model.AppError) { 18 role, err := a.Srv().Store.Role().Get(id) 19 if err != nil { 20 var nfErr *store.ErrNotFound 21 switch { 22 case errors.As(err, &nfErr): 23 return nil, model.NewAppError("GetRole", "app.role.get.app_error", nil, nfErr.Error(), http.StatusNotFound) 24 default: 25 return nil, model.NewAppError("GetRole", "app.role.get.app_error", nil, err.Error(), http.StatusInternalServerError) 26 } 27 } 28 29 return role, nil 30 } 31 32 func (a *App) GetAllRoles() ([]*model.Role, *model.AppError) { 33 roles, err := a.Srv().Store.Role().GetAll() 34 if err != nil { 35 return nil, model.NewAppError("GetAllRoles", "app.role.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 36 } 37 38 return roles, nil 39 } 40 41 func (s *Server) GetRoleByName(name string) (*model.Role, *model.AppError) { 42 role, nErr := s.Store.Role().GetByName(name) 43 if nErr != nil { 44 var nfErr *store.ErrNotFound 45 switch { 46 case errors.As(nErr, &nfErr): 47 return nil, model.NewAppError("GetRoleByName", "app.role.get_by_name.app_error", nil, nfErr.Error(), http.StatusNotFound) 48 default: 49 return nil, model.NewAppError("GetRoleByName", "app.role.get_by_name.app_error", nil, nErr.Error(), http.StatusInternalServerError) 50 } 51 } 52 53 err := s.mergeChannelHigherScopedPermissions([]*model.Role{role}) 54 if err != nil { 55 return nil, err 56 } 57 58 return role, nil 59 } 60 61 func (a *App) GetRoleByName(name string) (*model.Role, *model.AppError) { 62 return a.Srv().GetRoleByName(name) 63 } 64 65 func (a *App) GetRolesByNames(names []string) ([]*model.Role, *model.AppError) { 66 roles, nErr := a.Srv().Store.Role().GetByNames(names) 67 if nErr != nil { 68 return nil, model.NewAppError("GetRolesByNames", "app.role.get_by_names.app_error", nil, nErr.Error(), http.StatusInternalServerError) 69 } 70 71 err := a.mergeChannelHigherScopedPermissions(roles) 72 if err != nil { 73 return nil, err 74 } 75 76 return roles, nil 77 } 78 79 // mergeChannelHigherScopedPermissions updates the permissions based on the role type, whether the permission is 80 // moderated, and the value of the permission on the higher-scoped scheme. 81 func (s *Server) mergeChannelHigherScopedPermissions(roles []*model.Role) *model.AppError { 82 var higherScopeNamesToQuery []string 83 84 for _, role := range roles { 85 if role.SchemeManaged { 86 higherScopeNamesToQuery = append(higherScopeNamesToQuery, role.Name) 87 } 88 } 89 90 if len(higherScopeNamesToQuery) == 0 { 91 return nil 92 } 93 94 higherScopedPermissionsMap, err := s.Store.Role().ChannelHigherScopedPermissions(higherScopeNamesToQuery) 95 if err != nil { 96 return model.NewAppError("mergeChannelHigherScopedPermissions", "app.role.get_by_names.app_error", nil, err.Error(), http.StatusInternalServerError) 97 } 98 99 for _, role := range roles { 100 if role.SchemeManaged { 101 if higherScopedPermissions, ok := higherScopedPermissionsMap[role.Name]; ok { 102 role.MergeChannelHigherScopedPermissions(higherScopedPermissions) 103 } 104 } 105 } 106 107 return nil 108 } 109 110 // mergeChannelHigherScopedPermissions updates the permissions based on the role type, whether the permission is 111 // moderated, and the value of the permission on the higher-scoped scheme. 112 func (a *App) mergeChannelHigherScopedPermissions(roles []*model.Role) *model.AppError { 113 return a.Srv().mergeChannelHigherScopedPermissions(roles) 114 } 115 116 func (a *App) PatchRole(role *model.Role, patch *model.RolePatch) (*model.Role, *model.AppError) { 117 // If patch is a no-op then short-circuit the store. 118 if patch.Permissions != nil && reflect.DeepEqual(*patch.Permissions, role.Permissions) { 119 return role, nil 120 } 121 122 role.Patch(patch) 123 role, err := a.UpdateRole(role) 124 if err != nil { 125 return nil, err 126 } 127 128 return role, err 129 } 130 131 func (a *App) CreateRole(role *model.Role) (*model.Role, *model.AppError) { 132 role.Id = "" 133 role.CreateAt = 0 134 role.UpdateAt = 0 135 role.DeleteAt = 0 136 role.BuiltIn = false 137 role.SchemeManaged = false 138 139 var err error 140 role, err = a.Srv().Store.Role().Save(role) 141 if err != nil { 142 var invErr *store.ErrInvalidInput 143 switch { 144 case errors.As(err, &invErr): 145 return nil, model.NewAppError("CreateRole", "app.role.save.invalid_role.app_error", nil, invErr.Error(), http.StatusBadRequest) 146 default: 147 return nil, model.NewAppError("CreateRole", "app.role.save.insert.app_error", nil, err.Error(), http.StatusInternalServerError) 148 } 149 } 150 151 return role, nil 152 } 153 154 func (a *App) UpdateRole(role *model.Role) (*model.Role, *model.AppError) { 155 savedRole, err := a.Srv().Store.Role().Save(role) 156 if err != nil { 157 var invErr *store.ErrInvalidInput 158 switch { 159 case errors.As(err, &invErr): 160 return nil, model.NewAppError("UpdateRole", "app.role.save.invalid_role.app_error", nil, invErr.Error(), http.StatusBadRequest) 161 default: 162 return nil, model.NewAppError("UpdateRole", "app.role.save.insert.app_error", nil, err.Error(), http.StatusInternalServerError) 163 } 164 } 165 166 builtInChannelRoles := []string{ 167 model.CHANNEL_GUEST_ROLE_ID, 168 model.CHANNEL_USER_ROLE_ID, 169 model.CHANNEL_ADMIN_ROLE_ID, 170 } 171 172 builtInRolesMinusChannelRoles := utils.RemoveStringsFromSlice(model.BuiltInSchemeManagedRoleIDs, builtInChannelRoles...) 173 174 if utils.StringInSlice(savedRole.Name, builtInRolesMinusChannelRoles) { 175 return savedRole, nil 176 } 177 178 var roleRetrievalFunc func() ([]*model.Role, *model.AppError) 179 180 if utils.StringInSlice(savedRole.Name, builtInChannelRoles) { 181 roleRetrievalFunc = func() ([]*model.Role, *model.AppError) { 182 roles, nErr := a.Srv().Store.Role().AllChannelSchemeRoles() 183 if nErr != nil { 184 return nil, model.NewAppError("UpdateRole", "app.role.get.app_error", nil, nErr.Error(), http.StatusInternalServerError) 185 } 186 187 return roles, nil 188 } 189 } else { 190 roleRetrievalFunc = func() ([]*model.Role, *model.AppError) { 191 roles, nErr := a.Srv().Store.Role().ChannelRolesUnderTeamRole(savedRole.Name) 192 if nErr != nil { 193 return nil, model.NewAppError("UpdateRole", "app.role.get.app_error", nil, nErr.Error(), http.StatusInternalServerError) 194 } 195 196 return roles, nil 197 } 198 } 199 200 impactedRoles, appErr := roleRetrievalFunc() 201 if appErr != nil { 202 return nil, appErr 203 } 204 impactedRoles = append(impactedRoles, role) 205 206 appErr = a.mergeChannelHigherScopedPermissions(impactedRoles) 207 if appErr != nil { 208 return nil, appErr 209 } 210 211 for _, ir := range impactedRoles { 212 a.sendUpdatedRoleEvent(ir) 213 } 214 215 return savedRole, nil 216 } 217 218 func (a *App) CheckRolesExist(roleNames []string) *model.AppError { 219 roles, err := a.GetRolesByNames(roleNames) 220 if err != nil { 221 return err 222 } 223 224 for _, name := range roleNames { 225 nameFound := false 226 for _, role := range roles { 227 if name == role.Name { 228 nameFound = true 229 break 230 } 231 } 232 if !nameFound { 233 return model.NewAppError("CheckRolesExist", "app.role.check_roles_exist.role_not_found", nil, "role="+name, http.StatusBadRequest) 234 } 235 } 236 237 return nil 238 } 239 240 func (a *App) sendUpdatedRoleEvent(role *model.Role) { 241 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ROLE_UPDATED, "", "", "", nil) 242 message.Add("role", role.ToJson()) 243 244 a.Srv().Go(func() { 245 a.Publish(message) 246 }) 247 } 248 249 func RemoveRoles(rolesToRemove []string, roles string) string { 250 roleList := strings.Fields(roles) 251 newRoles := make([]string, 0) 252 253 for _, role := range roleList { 254 shouldRemove := false 255 for _, roleToRemove := range rolesToRemove { 256 if role == roleToRemove { 257 shouldRemove = true 258 break 259 } 260 } 261 if !shouldRemove { 262 newRoles = append(newRoles, role) 263 } 264 } 265 266 return strings.Join(newRoles, " ") 267 }