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  }