diff --git a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-edit-folder/dnn-rm-edit-folder.tsx b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-edit-folder/dnn-rm-edit-folder.tsx index 043187f1c7f..c7b88989f8f 100644 --- a/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-edit-folder/dnn-rm-edit-folder.tsx +++ b/DNN Platform/Modules/ResourceManager/ResourceManager.Web/src/components/dnn-rm-edit-folder/dnn-rm-edit-folder.tsx @@ -3,7 +3,7 @@ import { IRole } from '@dnncommunity/dnn-elements/dist/types/components/dnn-perm import { Component, Element, Event, EventEmitter, Host, h, State, Prop } from '@stencil/core'; import state from '../../store/store'; import { FolderDetails, ItemsClient, SaveFolderDetailsRequest } from '../../services/ItemsClient'; -import { IPermissions, IRolePermission, IUserPermission } from '@dnncommunity/dnn-elements/dist/types/components/dnn-permissions-grid/permissions-interface'; +import { IPermissionDefinition, IPermissions, IRolePermission, IUserPermission } from '@dnncommunity/dnn-elements/dist/types/components/dnn-permissions-grid/permissions-interface'; import { ISearchedUser } from '@dnncommunity/dnn-elements/dist/types/components/dnn-permissions-grid/searched-user-interface'; @Component({ tag: 'dnn-rm-edit-folder', @@ -28,6 +28,7 @@ export class DnnRmEditFolder { @State() folderIconUrl: string; @State() folderDetails: FolderDetails; @State() foundUsers: ISearchedUser[]; + @State() lastPermissions: IPermissions; private itemsClient: ItemsClient; @@ -90,6 +91,7 @@ export class DnnRmEditFolder { ], }, }; + this.lastPermissions = {...this.folderDetails.permissions}; }) .catch(error => alert(error)); @@ -130,128 +132,107 @@ export class DnnRmEditFolder { } private handlePermissionsChanged(newPermissions: IPermissions): void { - newPermissions.rolePermissions.forEach(rolePermission => this.adjustRelatedPermissions(rolePermission)); - newPermissions.userPermissions.forEach(userPermission => this.adjustRelatedPermissions(userPermission)); + // Get previous role permissions and adjust related permissions + newPermissions.rolePermissions.forEach(rolePermission => { + const previousPermissions = this.lastPermissions?.rolePermissions?.find(p => p.roleId === rolePermission.roleId).permissions ?? []; + this.adjustRelatedPermissions(rolePermission, previousPermissions); + }); + + // Get previous user permissions and adjust related permissions + newPermissions.userPermissions.forEach(userPermission => { + const previousPermissions = this.lastPermissions?.userPermissions?.find(p => p.userId === userPermission.userId).permissions ?? []; + this.adjustRelatedPermissions(userPermission, previousPermissions); + }); + + // Update the folder details with the new permissions this.folderDetails = { ...this.folderDetails, permissions: newPermissions, }; + + // Update the last known permissions state + this.lastPermissions = newPermissions; } - private adjustRelatedPermissions(permission: IRolePermission | IUserPermission): void { - const permissionId = - { + private adjustRelatedPermissions(permission: IRolePermission | IUserPermission, previousPermissions: IPermissionDefinition[]): void { + const permissionIds = { view: this.folderDetails.permissions.permissionDefinitions.find(p => p.permissionName === 'View Folder').permissionId, browse: this.folderDetails.permissions.permissionDefinitions.find(p => p.permissionName === 'Browse Folder').permissionId, write: this.folderDetails.permissions.permissionDefinitions.find(p => p.permissionName === 'Write to Folder').permissionId, }; + + const viewPermission = permission.permissions.find(p => p.permissionId === permissionIds.view); + const browsePermission = permission.permissions.find(p => p.permissionId === permissionIds.browse); + const writePermission = permission.permissions.find(p => p.permissionId === permissionIds.write); + + // Check if specific permissions have changed from the last known state + const viewChanged = viewPermission && this.hasPermissionChanged(previousPermissions, viewPermission, permissionIds.view); + const browseChanged = browsePermission && this.hasPermissionChanged(previousPermissions, browsePermission, permissionIds.browse); + const writeChanged = writePermission && this.hasPermissionChanged(previousPermissions, writePermission, permissionIds.write); - const viewPermission = permission.permissions.find(p => p.permissionId == permissionId.view); // If view permission is denied, then deny all other permissions - if (viewPermission && viewPermission.allowAccess == false){ - // Deny all permissions - permission.permissions = [ - { - allowAccess: false, - fullControl: false, - permissionId: permissionId.view, - permissionCode: null, - permissionKey: null, - permissionName: "View Folder", - view: false, - }, - { - allowAccess: false, - fullControl: false, - permissionId: permissionId.browse, - permissionCode: null, - permissionKey: null, - permissionName: "Browse Folder", - view: false, - }, - { - allowAccess: false, - fullControl: false, - permissionId: permissionId.write, - permissionCode: null, - permissionKey: null, - permissionName: "Write to Folder", - view: false, - }, - ] + if (viewChanged && !viewPermission.allowAccess) { + if (browsePermission) { + browsePermission.allowAccess = false; + } + if (writePermission) { + writePermission.allowAccess = false; + } } - + // If browse was denied, then deny write - const browsePermission = permission.permissions.find(p => p.permissionId == permissionId.browse); - if (browsePermission && browsePermission.allowAccess == false){ - // Deny write - permission.permissions = [ - ...permission.permissions.filter(p => p.permissionId != permissionId.write), - { - allowAccess: false, - fullControl: false, - permissionId: permissionId.write, - permissionCode: null, - permissionKey: null, - permissionName: "Write to Folder", - view: false, - } - ] + if (browseChanged && !browsePermission.allowAccess && writePermission) { + writePermission.allowAccess = false; } - + // If browse was allowed, then allow view - if (browsePermission && browsePermission.allowAccess == true){ - // Allow browse - permission.permissions = [ - { + if (browseChanged && browsePermission.allowAccess) { + if (!viewPermission) { + // Create a new list with all existing permissions plus the new view permission + permission.permissions = [...permission.permissions, { + permissionId: permissionIds.view, allowAccess: true, fullControl: false, - permissionId: permissionId.view, permissionCode: null, permissionKey: null, - permissionName: "Browse Folder", + permissionName: "View Folder", view: false, - }, - ...permission.permissions.filter(p => p.permissionId != permissionId.view), - ]; + }]; + } else { + viewPermission.allowAccess = true; + } } - + // If write was allowed, then allow all other permissions - const writePermission = permission.permissions.find(p => p.permissionId == permissionId.write); - if (writePermission && writePermission.allowAccess == true){ - // Allow all permissions + if (writeChanged && writePermission.allowAccess) { permission.permissions = [ + ...permission.permissions.filter(p => ![permissionIds.view, permissionIds.browse].includes(p.permissionId)), { + permissionId: permissionIds.view, allowAccess: true, fullControl: false, - permissionId: permissionId.view, permissionCode: null, permissionKey: null, permissionName: "View Folder", view: false, }, { - allowAccess: true, - fullControl: false, - permissionId: permissionId.browse, - permissionCode: null, - permissionKey: null, - permissionName: "Browse Folder", - view: false, - }, - { - allowAccess: true, - fullControl: false, - permissionId: permissionId.write, - permissionCode: null, - permissionKey: null, - permissionName: "Write to Folder", - view: false, - }, - ] + permissionId: permissionIds.browse, + allowAccess: true, + fullControl: false, + permissionCode: null, + permissionKey: null, + permissionName: "Browse Folder", + view: false, + }]; } } + private hasPermissionChanged(lastPermissions: IPermissionDefinition[], currentPermission: IPermissionDefinition, permissionId: number): boolean { + const lastPermission = lastPermissions.find(p => p.permissionId === permissionId) + return !lastPermission || JSON.stringify(lastPermission) !== JSON.stringify(currentPermission); + } + private handleUserSearchQueryChanged(detail: string): void { this.itemsClient.searchUsers(detail) .then(data => this.foundUsers = data) diff --git a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.13.04.SqlDataProvider b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.13.04.SqlDataProvider index 2480b0278c1..8b3f37f3196 100644 --- a/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.13.04.SqlDataProvider +++ b/DNN Platform/Website/Providers/DataProviders/SqlDataProvider/09.13.04.SqlDataProvider @@ -1,98 +1,115 @@ -/************************************************************/ -/***** SqlDataProvider *****/ -/***** *****/ -/***** *****/ -/***** Note: To manually execute this script you must *****/ -/***** perform a search and replace operation *****/ -/***** for {databaseOwner} and {objectQualifier} *****/ -/***** *****/ -/************************************************************/ - -/* Fix Deleted Date for Recycle Bin Items #6074 */ -/**************************************/ - -IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}vw_Modules]', N'V') IS NOT NULL - DROP VIEW {databaseOwner}[{objectQualifier}vw_Modules] -GO - -CREATE VIEW {databaseOwner}[{objectQualifier}vw_Modules] -AS - SELECT - M.PortalID AS [OwnerPortalID], - DM.PackageID, - T.PortalID, - TM.TabID, - TM.TabModuleID, - M.ModuleID, - M.ModuleDefID, - TM.ModuleOrder, - TM.PaneName, - TM.ModuleTitle, - TM.CacheTime, - TM.CacheMethod, - TM.Alignment, - TM.Color, - TM.Border, - CASE WHEN TM.IconFile LIKE 'fileid=%' - THEN (SELECT IsNull(Folder, '') + [FileName] FROM {databaseOwner}[{objectQualifier}vw_Files] - WHERE FileId = CAST(SUBSTRING(TM.IconFile, 8, 10) AS Int)) - ELSE Coalesce(TM.IconFile,'') - END AS IconFile, - TM.Visibility, - TM.Header, - TM.Footer, - TM.ContainerSrc, - TM.DisplayTitle, - TM.DisplayPrint, - TM.DisplaySyndicate, - TM.IsWebSlice, - TM.WebSliceTitle, - TM.WebSliceExpiryDate, - TM.WebSliceTTL, - TM.UniqueId, - TM.VersionGuid, - TM.DefaultLanguageGuid, - TM.LocalizedVersionGuid, - TM.CultureCode, - M.AllTabs, - M.StartDate, - M.EndDate, - T.StartDate AS TabStartDate, - T.EndDate AS TabEndDate, - M.InheritViewPermissions, - M.IsShareable, - M.IsShareableViewOnly, - TM.CreatedByUserID, - TM.CreatedOnDate, - TM.LastModifiedByUserID, - TM.LastModifiedOnDate, - M.LastContentModifiedOnDate, - MD.DesktopModuleID, - MD.DefaultCacheTime, - MD.DefinitionName, - MC.ModuleControlID, - DM.BusinessControllerClass, - DM.IsAdmin, - DM.SupportedFeatures, - CI.ContentItemID, - CI.Content, - CI.ContentTypeID, - CI.ContentKey, - CI.Indexed, - CI.StateID, - TM.IsDeleted AS IsDeleted, - M.IsDeleted AS IsModuleDeleted, - T.IsDeleted AS IsTabDeleted - FROM {databaseOwner}[{objectQualifier}ModuleDefinitions] AS MD - INNER JOIN {databaseOwner}[{objectQualifier}Modules] AS M ON M.ModuleDefID = MD.ModuleDefID - INNER JOIN {databaseOwner}[{objectQualifier}ModuleControls] AS MC ON MD.ModuleDefID = MC.ModuleDefID - INNER JOIN {databaseOwner}[{objectQualifier}DesktopModules] AS DM ON MD.DesktopModuleID = DM.DesktopModuleID - LEFT JOIN {databaseOwner}[{objectQualifier}ContentItems] AS CI ON M.ContentItemID = CI.ContentItemID - LEFT JOIN {databaseOwner}[{objectQualifier}TabModules] AS TM ON M.ModuleID = TM.ModuleID - LEFT JOIN {databaseOwner}[{objectQualifier}Tabs] AS T ON TM.TabID = T.TabID - WHERE (MC.ControlKey IS NULL) -GO - -/************************************************************/ -/***** SqlDataProvider *****/ -/************************************************************/ +/************************************************************/ +/***** SqlDataProvider *****/ +/***** *****/ +/***** *****/ +/***** Note: To manually execute this script you must *****/ +/***** perform a search and replace operation *****/ +/***** for {databaseOwner} and {objectQualifier} *****/ +/***** *****/ +/************************************************************/ + +/* update procedure GetFolderPermissionsByPortalAndPath to lookup null values for portalID */ +/*******************************************/ + +if exists (select * from dbo.sysobjects where id = object_id(N'{databaseOwner}[{objectQualifier}GetFolderPermissionsByPortalAndPath]') AND type in (N'P', N'PC')) + DROP PROCEDURE {databaseOwner}[{objectQualifier}GetFolderPermissionsByPortalAndPath] +GO + + CREATE PROCEDURE {databaseOwner}[{objectQualifier}GetFolderPermissionsByPortalAndPath] + @portalid int, + @FolderPath nvarchar(300) + AS + BEGIN + + SELECT * + FROM {databaseOwner}[{objectQualifier}vw_FolderPermissions] + WHERE (PortalID = IsNull(@portalid, -1) OR (@portalid IS NULL AND PortalID IS NULL)) AND (FolderPath = @FolderPath OR @FolderPath IS NULL) + END + +GO + + +/* Fix Deleted Date for Recycle Bin Items #6074 */ +/**************************************/ + +IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}vw_Modules]', N'V') IS NOT NULL + DROP VIEW {databaseOwner}[{objectQualifier}vw_Modules] +GO + +CREATE VIEW {databaseOwner}[{objectQualifier}vw_Modules] +AS + SELECT + M.PortalID AS [OwnerPortalID], + DM.PackageID, + T.PortalID, + TM.TabID, + TM.TabModuleID, + M.ModuleID, + M.ModuleDefID, + TM.ModuleOrder, + TM.PaneName, + TM.ModuleTitle, + TM.CacheTime, + TM.CacheMethod, + TM.Alignment, + TM.Color, + TM.Border, + CASE WHEN TM.IconFile LIKE 'fileid=%' + THEN (SELECT IsNull(Folder, '') + [FileName] FROM {databaseOwner}[{objectQualifier}vw_Files] + WHERE FileId = CAST(SUBSTRING(TM.IconFile, 8, 10) AS Int)) + ELSE Coalesce(TM.IconFile,'') + END AS IconFile, + TM.Visibility, + TM.Header, + TM.Footer, + TM.ContainerSrc, + TM.DisplayTitle, + TM.DisplayPrint, + TM.DisplaySyndicate, + TM.IsWebSlice, + TM.WebSliceTitle, + TM.WebSliceExpiryDate, + TM.WebSliceTTL, + TM.UniqueId, + TM.VersionGuid, + TM.DefaultLanguageGuid, + TM.LocalizedVersionGuid, + TM.CultureCode, + M.AllTabs, + M.StartDate, + M.EndDate, + T.StartDate AS TabStartDate, + T.EndDate AS TabEndDate, + M.InheritViewPermissions, + M.IsShareable, + M.IsShareableViewOnly, + TM.CreatedByUserID, + TM.CreatedOnDate, + TM.LastModifiedByUserID, + TM.LastModifiedOnDate, + M.LastContentModifiedOnDate, + MD.DesktopModuleID, + MD.DefaultCacheTime, + MD.DefinitionName, + MC.ModuleControlID, + DM.BusinessControllerClass, + DM.IsAdmin, + DM.SupportedFeatures, + CI.ContentItemID, + CI.Content, + CI.ContentTypeID, + CI.ContentKey, + CI.Indexed, + CI.StateID, + TM.IsDeleted AS IsDeleted, + M.IsDeleted AS IsModuleDeleted, + T.IsDeleted AS IsTabDeleted + FROM {databaseOwner}[{objectQualifier}ModuleDefinitions] AS MD + INNER JOIN {databaseOwner}[{objectQualifier}Modules] AS M ON M.ModuleDefID = MD.ModuleDefID + INNER JOIN {databaseOwner}[{objectQualifier}ModuleControls] AS MC ON MD.ModuleDefID = MC.ModuleDefID + INNER JOIN {databaseOwner}[{objectQualifier}DesktopModules] AS DM ON MD.DesktopModuleID = DM.DesktopModuleID + LEFT JOIN {databaseOwner}[{objectQualifier}ContentItems] AS CI ON M.ContentItemID = CI.ContentItemID + LEFT JOIN {databaseOwner}[{objectQualifier}TabModules] AS TM ON M.ModuleID = TM.ModuleID + LEFT JOIN {databaseOwner}[{objectQualifier}Tabs] AS T ON TM.TabID = T.TabID + WHERE (MC.ControlKey IS NULL) +GO