[MM-22206] Add PATCH channel moderations (PUT /moderations/patch) (#13845)

* MM-22205 Add get channel moderations endpoint

* MM-22206 Add patch channel moderations endpoint

Add api tests for patch channel moderations

* MM-22205 Ensure ordered permissions returned and create struct ChannelModeratedRoles

* MM-22206 Use structs instead of map

* MM-22206 Add test cases for GetChannelModeratedPermissions

* MM-22206 Add tests for ChannelModeratedPermissionsChangedByPatch

* MM-22206 Use NewBool instead of defining booleans

* MM-22206 Tie Channel Mentions to Create Posts when building Channel Moderations

* Revert "MM-22206 Tie Channel Mentions to Create Posts when building Channel Moderations"

This reverts commit a0bfc95f1732955c5ef5fc3e4b05ea8ab954acea.

* MM-22206 Review changes

Modify GetSchemeRolesForChannel to return named variables
Change calls to SessionHasPermissionToChannel to SessionHasPermissionTo
Add a CreateChannelScheme method
Add a DeleteChannelScheme method
Move GetChannelModeratedPermissions to Role model

* Fix lint

* Add ChannelModeration methods to App interface

* MM-22206 Rename method to GetTeamSchemeChannelRoles

* MM-22206 Check CHANNEL_MODERATED_PERMISSIONS_MAP for existing permission before iterating through it

* Modify wording to higherScoped to match #13813

* MM-22206 Delete channel scheme between tests

* MM-22206 Fix tests

* Actually patch role

* MM-22206 Shadow declaration of err
Этот коммит содержится в:
Farhan Munshi
2020-03-05 10:04:34 -05:00
коммит произвёл GitHub
родитель bfde6d1f3e
Коммит 79c786bc0c
13 изменённых файлов: 1331 добавлений и 18 удалений

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

@@ -547,6 +547,34 @@ func (a *App) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppE
return channel, nil
}
// CreateChannelScheme creates a new Scheme of scope channel and assigns it to the channel.
func (a *App) CreateChannelScheme(channel *model.Channel) (*model.Scheme, *model.AppError) {
scheme, err := a.CreateScheme(&model.Scheme{
Name: model.NewId(),
DisplayName: model.NewId(),
Scope: model.SCHEME_SCOPE_CHANNEL,
})
if err != nil {
return nil, err
}
channel.SchemeId = &scheme.Id
if _, err := a.UpdateChannelScheme(channel); err != nil {
return nil, err
}
return scheme, nil
}
// DeleteChannelScheme deletes a channels scheme and sets its SchemeId to nil.
func (a *App) DeleteChannelScheme(channel *model.Channel) (*model.Channel, *model.AppError) {
if _, err := a.DeleteScheme(*channel.SchemeId); err != nil {
return nil, err
}
channel.SchemeId = nil
return a.UpdateChannelScheme(channel)
}
// UpdateChannelScheme saves the new SchemeId of the channel passed.
func (a *App) UpdateChannelScheme(channel *model.Channel) (*model.Channel, *model.AppError) {
var oldChannel *model.Channel
var err *model.AppError
@@ -555,13 +583,7 @@ func (a *App) UpdateChannelScheme(channel *model.Channel) (*model.Channel, *mode
}
oldChannel.SchemeId = channel.SchemeId
newChannel, err := a.UpdateChannel(oldChannel)
if err != nil {
return nil, err
}
return newChannel, nil
return a.UpdateChannel(oldChannel)
}
func (a *App) UpdateChannelPrivacy(oldChannel *model.Channel, user *model.User) (*model.Channel, *model.AppError) {
@@ -685,35 +707,185 @@ func (a *App) PatchChannel(channel *model.Channel, patch *model.ChannelPatch, us
return channel, nil
}
func (a *App) GetSchemeRolesForChannel(channelId string) (string, string, string, *model.AppError) {
// GetSchemeRolesForChannel Checks if a channel or its team has an override scheme for channel roles and returns the scheme roles or default channel roles.
func (a *App) GetSchemeRolesForChannel(channelId string) (guestRoleName, userRoleName, adminRoleName string, err *model.AppError) {
channel, err := a.GetChannel(channelId)
if err != nil {
return "", "", "", err
return
}
if channel.SchemeId != nil && len(*channel.SchemeId) != 0 {
var scheme *model.Scheme
scheme, err = a.GetScheme(*channel.SchemeId)
if err != nil {
return "", "", "", err
return
}
return scheme.DefaultChannelGuestRole, scheme.DefaultChannelUserRole, scheme.DefaultChannelAdminRole, nil
guestRoleName = scheme.DefaultChannelGuestRole
userRoleName = scheme.DefaultChannelUserRole
adminRoleName = scheme.DefaultChannelAdminRole
return
}
team, err := a.GetTeam(channel.TeamId)
return a.GetTeamSchemeChannelRoles(channel.TeamId)
}
// GetTeamSchemeChannelRoles Checks if a team has an override scheme and returns the scheme channel role names or default channel role names.
func (a *App) GetTeamSchemeChannelRoles(teamId string) (guestRoleName, userRoleName, adminRoleName string, err *model.AppError) {
team, err := a.GetTeam(teamId)
if err != nil {
return "", "", "", err
return
}
if team.SchemeId != nil && len(*team.SchemeId) != 0 {
scheme, err := a.GetScheme(*team.SchemeId)
var scheme *model.Scheme
scheme, err = a.GetScheme(*team.SchemeId)
if err != nil {
return "", "", "", err
return
}
return scheme.DefaultChannelGuestRole, scheme.DefaultChannelUserRole, scheme.DefaultChannelAdminRole, nil
guestRoleName = scheme.DefaultChannelGuestRole
userRoleName = scheme.DefaultChannelUserRole
adminRoleName = scheme.DefaultChannelAdminRole
} else {
guestRoleName = model.CHANNEL_GUEST_ROLE_ID
userRoleName = model.CHANNEL_USER_ROLE_ID
adminRoleName = model.CHANNEL_ADMIN_ROLE_ID
}
return model.CHANNEL_GUEST_ROLE_ID, model.CHANNEL_USER_ROLE_ID, model.CHANNEL_ADMIN_ROLE_ID, nil
return
}
// PatchChannelModerationsForChannel Gets a channels ChannelModerations from either the higherScoped roles or from the channel scheme roles.
func (a *App) GetChannelModerationsForChannel(channel *model.Channel) ([]*model.ChannelModeration, *model.AppError) {
guestRoleName, memberRoleName, _, _ := a.GetSchemeRolesForChannel(channel.Id)
memberRole, err := a.GetRoleByName(memberRoleName)
if err != nil {
return nil, err
}
guestRole, err := a.GetRoleByName(guestRoleName)
if err != nil {
return nil, err
}
higherScopedGuestRoleName, higherScopedMemberRoleName, _, _ := a.GetTeamSchemeChannelRoles(channel.TeamId)
higherScopedMemberRole, err := a.GetRoleByName(higherScopedMemberRoleName)
if err != nil {
return nil, err
}
higherScopedGuestRole, err := a.GetRoleByName(higherScopedGuestRoleName)
if err != nil {
return nil, err
}
return buildChannelModerations(memberRole, guestRole, higherScopedMemberRole, higherScopedGuestRole), nil
}
// PatchChannelModerationsForChannel Updates a channels scheme roles based on a given ChannelModerationPatch, if the permissions match the higher scoped role the scheme is deleted.
func (a *App) PatchChannelModerationsForChannel(channel *model.Channel, channelModerationsPatch []*model.ChannelModerationPatch) ([]*model.ChannelModeration, *model.AppError) {
higherScopedGuestRoleName, higherScopedMemberRoleName, _, _ := a.GetTeamSchemeChannelRoles(channel.TeamId)
higherScopedMemberRole, err := a.GetRoleByName(higherScopedMemberRoleName)
if err != nil {
return nil, err
}
higherScopedGuestRole, err := a.GetRoleByName(higherScopedGuestRoleName)
if err != nil {
return nil, err
}
higherScopedMemberPermissions := higherScopedMemberRole.GetChannelModeratedPermissions()
higherScopedGuestPermissions := higherScopedGuestRole.GetChannelModeratedPermissions()
for _, moderationPatch := range channelModerationsPatch {
if moderationPatch.Roles.Members != nil && *moderationPatch.Roles.Members && !higherScopedMemberPermissions[*moderationPatch.Name] {
return nil, &model.AppError{Message: "Cannot add a permission that is restricted by the team or system permission scheme"}
}
if moderationPatch.Roles.Guests != nil && *moderationPatch.Roles.Guests && !higherScopedGuestPermissions[*moderationPatch.Name] {
return nil, &model.AppError{Message: "Cannot add a permission that is restricted by the team or system permission scheme"}
}
}
// Channel has no scheme so create one
if channel.SchemeId == nil || len(*channel.SchemeId) == 0 {
if _, err = a.CreateChannelScheme(channel); err != nil {
return nil, err
}
}
guestRoleName, memberRoleName, _, _ := a.GetSchemeRolesForChannel(channel.Id)
memberRole, err := a.GetRoleByName(memberRoleName)
if err != nil {
return nil, err
}
guestRole, err := a.GetRoleByName(guestRoleName)
if err != nil {
return nil, err
}
memberRolePatch := memberRole.RolePatchFromChannelModerationsPatch(channelModerationsPatch, "members")
guestRolePatch := guestRole.RolePatchFromChannelModerationsPatch(channelModerationsPatch, "guests")
memberRolePermissionsUnmodified := len(model.ChannelModeratedPermissionsChangedByPatch(higherScopedMemberRole, memberRolePatch)) == 0
guestRolePermissionsUnmodified := len(model.ChannelModeratedPermissionsChangedByPatch(higherScopedGuestRole, guestRolePatch)) == 0
if memberRolePermissionsUnmodified && guestRolePermissionsUnmodified {
// The channel scheme matches the permissions of its higherScoped scheme so delete the scheme
if _, err = a.DeleteChannelScheme(channel); err != nil {
return nil, err
}
memberRole = higherScopedMemberRole
guestRole = higherScopedGuestRole
} else {
memberRole, err = a.PatchRole(memberRole, memberRolePatch)
if err != nil {
return nil, err
}
guestRole, err = a.PatchRole(guestRole, guestRolePatch)
if err != nil {
return nil, err
}
}
return buildChannelModerations(memberRole, guestRole, higherScopedMemberRole, higherScopedGuestRole), nil
}
func buildChannelModerations(memberRole *model.Role, guestRole *model.Role, higherScopedMemberRole *model.Role, higherScopedGuestRole *model.Role) []*model.ChannelModeration {
memberPermissions := memberRole.GetChannelModeratedPermissions()
guestPermissions := guestRole.GetChannelModeratedPermissions()
higherScopedMemberPermissions := higherScopedMemberRole.GetChannelModeratedPermissions()
higherScopedGuestPermissions := higherScopedGuestRole.GetChannelModeratedPermissions()
var channelModerations []*model.ChannelModeration
for _, permissionKey := range model.CHANNEL_MODERATED_PERMISSIONS {
roles := &model.ChannelModeratedRoles{}
roles.Members = &model.ChannelModeratedRole{
Value: memberPermissions[permissionKey],
Enabled: higherScopedMemberPermissions[permissionKey],
}
if permissionKey == "manage_members" {
roles.Guests = nil
} else {
roles.Guests = &model.ChannelModeratedRole{
Value: guestPermissions[permissionKey],
Enabled: higherScopedGuestPermissions[permissionKey],
}
}
moderation := &model.ChannelModeration{
Name: permissionKey,
Roles: roles,
}
channelModerations = append(channelModerations, moderation)
}
return channelModerations
}
func (a *App) UpdateChannelMemberRoles(channelId string, userId string, newRoles string) (*model.ChannelMember, *model.AppError) {