# Rights to Permissions Migration Script # This script migrates Rights constants to PermissionId enums using a hybrid approach # # PURPOSE: # Automate the migration from the legacy Rights system (static classes with string constants) # to the new Permissions system (enum-based PermissionId) in BIA Framework projects. # # OPERATIONS PERFORMED: # 1. Extract all constants from Rights.cs file # - Parses all static classes and their const string definitions # - Extracts: class name, constant name, and constant value # - Excludes Announcement* classes (handled separately in manual dictionary) # # 2. Generate PermissionId enum entries # - Adds new enum values to PermissionId.cs before the "// BIAToolKit - Begin Permissions" marker # - Skips duplicates if they already exist # - Uses constant values directly as enum names (e.g., "Site_List_Access") # # 3. Replace all Rights and BiaRights references # - Scans all .cs files (excluding bin/obj folders and Rights.cs itself) # - Rights.ClassName.ConstName -> nameof(PermissionId.Value) - automatic from Rights.cs parsing # - BiaRights patterns -> nameof(BiaPermissionId.Value) - from manual dictionary $biaRightsReplacements # - Rights.Announcements.* -> nameof(BiaPermissionId.Announcement_*) - from manual dictionary # - String literals (e.g., "Background_Task_Admin") - from manual dictionary # - Suffixes patterns -> BiaPermissionSuffixes.* - from manual dictionary # # 4. Delete the Rights.cs file # # MANUAL DICTIONARY: # The $biaRightsReplacements hashtable must be filled with: # - All BiaRights.* references (BIA Framework rights) # - All Rights.Announcements.* references (project announcements using BiaPermissionId) # - String literal permissions that need replacement # - Permission suffixes mappings to BiaPermissionSuffixes # # EXAMPLES OF TRANSFORMATIONS: # Automatic (from Rights.cs parsing): # Rights.Sites.ListAccess -> nameof(PermissionId.Site_List_Access) # # Manual (from $biaRightsReplacements dictionary): # BiaRights.Home.Access -> nameof(BiaPermissionId.Home_Access) # Rights.Announcements.Read -> nameof(BiaPermissionId.Announcement_Read) # "Background_Task_Admin" -> nameof(BiaPermissionId.Background_Task_Admin) # BiaRights.Members.ListAccessSuffix -> BiaPermissionSuffixes.Members.ListAccessSuffix # # USAGE: # 1. Fill the $biaRightsReplacements dictionary with your BiaRights, Announcements, and special patterns # 2. Update $BackendPath variable below # 3. Run: .\migrate-rights-to-permissions.ps1 # Define the backend path (adapt according to your project) $BackendPath = "C:\sources\BIADemo\DotNet" # Manual dictionary for BiaRights replacements # Format: "BiaRights.ClassName.ConstName" = "nameof(BiaPermissionId.Value)" $biaRightsReplacements = @{ # BIA Framework Rights replacements # TODO: Fill this dictionary with your BiaRights constants # Example: # "BiaRights.Home.Access" = "nameof(BiaPermissionId.Home_Access)" "BiaRights.Roles.Options" = "nameof(BiaPermissionId.Roles_Options)" "BiaRights.Roles.ListForCurrentUser" = "nameof(BiaPermissionId.Roles_List_For_Current_User)" "BiaRights.Permissions.Options" = "nameof(BiaPermissionId.Permissions_Options)" "BiaRights.LdapDomains.List" = "nameof(BiaPermissionId.LdapDomains_List)" "BiaRights.Languages.Options" = "nameof(BiaPermissionId.Languages_Options)" "BiaRights.ProfileImage.Get" = "nameof(BiaPermissionId.ProfileImage_Get)" "BiaRights.Home.Access" = "nameof(BiaPermissionId.Home_Access)" "BiaRights.Logs.Create" = "nameof(BiaPermissionId.Logs_Create)" "BiaRights.Teams.Options" = "nameof(BiaPermissionId.Team_Options)" "BiaRights.Teams.AccessAll" = "nameof(BiaPermissionId.Team_Access_All)" "BiaRights.Teams.ListAccess" = "nameof(BiaPermissionId.Team_List_Access)" "BiaRights.Teams.SetDefaultTeam" = "nameof(BiaPermissionId.Team_Set_Default_Team)" "BiaRights.Teams.SetDefaultRoles" = "nameof(BiaPermissionId.Team_Set_Default_Roles)" "BiaRights.Users.Options" = "nameof(BiaPermissionId.User_Options)" "BiaRights.Users.ListAccess" = "nameof(BiaPermissionId.User_List_Access)" "BiaRights.Users.List" = "nameof(BiaPermissionId.User_List)" "BiaRights.Users.ListAD" = "nameof(BiaPermissionId.User_List_AD)" "BiaRights.Users.Read" = "nameof(BiaPermissionId.User_Read)" "BiaRights.Users.Add" = "nameof(BiaPermissionId.User_Add)" "BiaRights.Users.Delete" = "nameof(BiaPermissionId.User_Delete)" "BiaRights.Users.Save" = "nameof(BiaPermissionId.User_Save)" "BiaRights.Users.Sync" = "nameof(BiaPermissionId.User_Sync)" "BiaRights.Users.UpdateRoles" = "nameof(BiaPermissionId.User_Update_Roles)" "BiaRights.Views.Read" = "nameof(BiaPermissionId.View_Read)" "BiaRights.Views.List" = "nameof(BiaPermissionId.View_List)" "BiaRights.Views.AddUserView" = "nameof(BiaPermissionId.View_Add_UserView)" "BiaRights.Views.UpdateUserView" = "nameof(BiaPermissionId.View_Update_UserView)" "BiaRights.Views.DeleteUserView" = "nameof(BiaPermissionId.View_Delete_UserView)" "BiaRights.Views.DeleteTeamView" = "nameof(BiaPermissionId.View_Delete_TeamView)" "BiaRights.Views.SetDefaultUserView" = "nameof(BiaPermissionId.View_Set_Default_UserView)" "BiaRights.Notifications.ListAccess" = "nameof(BiaPermissionId.Notification_List_Access)" "BiaRights.Notifications.Read" = "nameof(BiaPermissionId.Notification_Read)" "BiaRights.Notifications.Create" = "nameof(BiaPermissionId.Notification_Create)" "BiaRights.Notifications.Update" = "nameof(BiaPermissionId.Notification_Update)" "BiaRights.Notifications.Delete" = "nameof(BiaPermissionId.Notification_Delete)" "BiaRights.NotificationTypes.Options" = "nameof(BiaPermissionId.NotificationType_Options)" "BiaRights.Impersonation.ConnectionRights" = "nameof(BiaPermissionId.Impersonation_Connection_Rights)" "Rights.Announcements.ListAccess" = "nameof(BiaPermissionId.Announcement_List_Access)" "Rights.Announcements.Create" = "nameof(BiaPermissionId.Announcement_Create)" "Rights.Announcements.Read" = "nameof(BiaPermissionId.Announcement_Read)" "Rights.Announcements.Update" = "nameof(BiaPermissionId.Announcement_Update)" "Rights.Announcements.Delete" = "nameof(BiaPermissionId.Announcement_Delete)" "Rights.Announcements.Save" = "nameof(BiaPermissionId.Announcement_Save)" "Rights.AnnouncementTypeOptions.Options" = "nameof(BiaPermissionId.AnnouncementType_Options)" "`"Background_Task_Admin`"" = "nameof(BiaPermissionId.Background_Task_Admin)" "`"Background_Task_Read_Only`"" = "nameof(BiaPermissionId.Background_Task_Read_Only)" # Suffixes "BiaRights.Members.ListAccessSuffix" = "BiaPermissionSuffixes.Members.ListAccessSuffix" "BiaRights.Members.CreateSuffix" = "BiaPermissionSuffixes.Members.CreateSuffix" "BiaRights.Members.ReadSuffix" = "BiaPermissionSuffixes.Members.ReadSuffix" "BiaRights.Members.UpdateSuffix" = "BiaPermissionSuffixes.Members.UpdateSuffix" "BiaRights.Members.DeleteSuffix" = "BiaPermissionSuffixes.Members.DeleteSuffix" "BiaRights.Members.SaveSuffix" = "BiaPermissionSuffixes.Members.SaveSuffix" "BiaRights.Views.AddTeamViewSuffix" = "BiaPermissionSuffixes.TeamViews.AddTeamViewSuffix" "BiaRights.Views.UpdateTeamViewSuffix" = "BiaPermissionSuffixes.TeamViews.UpdateTeamViewSuffix" "BiaRights.Views.SetDefaultTeamViewSuffix" = "BiaPermissionSuffixes.TeamViews.SetDefaultTeamViewSuffix" "BiaRights.Views.AssignToTeamSuffix" = "BiaPermissionSuffixes.TeamViews.AssignToTeamSuffix" } Write-Host "=== Starting Rights to Permissions Migration ===" -ForegroundColor Cyan Write-Host "Backend path: $BackendPath" -ForegroundColor Gray # Function to extract constants from Rights.cs file function Get-RightsConstants { param([string]$RightsFilePath) Write-Host "`nStep 1: Extracting constants from Rights.cs..." -ForegroundColor Yellow if (-not (Test-Path $RightsFilePath)) { Write-Host "ERROR: Rights.cs file not found at: $RightsFilePath" -ForegroundColor Red return @{Constants = @(); Replacements = @{}} } $content = Get-Content $RightsFilePath -Raw $constants = @() $replacements = @{} # Pattern to extract all static classes $classPattern = 'public\s+static\s+class\s+(\w+)\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}' $classMatches = [regex]::Matches($content, $classPattern) foreach ($classMatch in $classMatches) { $className = $classMatch.Groups[1].Value $classBody = $classMatch.Groups[2].Value # Special case: Announcements class uses BiaPermissionId if ($className -like "Announcement*") { continue; } # Pattern to extract all const string in this class $constPattern = 'public\s+const\s+string\s+(\w+)\s*=\s*"([^"]+)"' $constMatches = [regex]::Matches($classBody, $constPattern) foreach ($constMatch in $constMatches) { $constName = $constMatch.Groups[1].Value $constValue = $constMatch.Groups[2].Value # Store constant info for PermissionId.cs generation $constants += [PSCustomObject]@{ ClassName = $className ConstName = $constName Value = $constValue FullPath = "Rights.$className.$constName" } # Build the replacement mapping using the actual constant value $oldReference = "Rights.$className.$constName" $newReference = "nameof(PermissionId.$constValue)" $replacements[$oldReference] = $newReference Write-Host " Found: $oldReference = `"$constValue`" -> $newReference" -ForegroundColor Gray } } Write-Host "Total of $($constants.Count) constants extracted." -ForegroundColor Green return @{Constants = $constants; Replacements = $replacements} } # Function to convert a description with underscores to readable text function Get-Description { param([string]$Value) return $Value -replace '_', ' ' } # Function to generate the enum name based on the value function Get-EnumName { param([string]$Value) # The enum name is simply the value (already in correct format) return $Value } # Function to add permissions to PermissionId.cs function Add-PermissionsToEnum { param( [string]$PermissionIdPath, [array]$Constants ) Write-Host "`nStep 2: Adding permissions to PermissionId.cs..." -ForegroundColor Yellow if (-not (Test-Path $PermissionIdPath)) { Write-Host "ERROR: PermissionId.cs file not found at: $PermissionIdPath" -ForegroundColor Red return $false } $content = Get-Content $PermissionIdPath -Raw # Search for the marker line $marker = "// BIAToolKit - Begin PermissionId" if ($content -notmatch [regex]::Escape($marker)) { Write-Host "ERROR: The marker '$marker' was not found in PermissionId.cs" -ForegroundColor Red return $false } # Extract existing enums $existingEnumsPattern = '^\s*(\w+),?\s*$' $lines = $content -split "`r?`n" $existingEnums = @() foreach ($line in $lines) { if ($line -match $existingEnumsPattern -and $line -notmatch '^\s*//' -and $line -notmatch 'enum|{|}') { $enumName = $matches[1].Trim(',').Trim() if ($enumName) { $existingEnums += $enumName } } } Write-Host " Existing enums detected: $($existingEnums.Count)" -ForegroundColor Gray # Filter constants to exclude existing enums and remove duplicates by value $uniqueConstants = @() $seenValues = @{} foreach ($const in $Constants) { $enumName = Get-EnumName -Value $const.Value # Skip if already exists in PermissionId.cs if ($existingEnums -contains $enumName) { continue } # Skip if we've already seen this value (handle duplicates in Rights.cs) if ($seenValues.ContainsKey($enumName)) { Write-Host " Duplicate value detected: $enumName (from $($const.ClassName).$($const.ConstName), already added from $($seenValues[$enumName]))" -ForegroundColor Yellow continue } $seenValues[$enumName] = "$($const.ClassName).$($const.ConstName)" $uniqueConstants += $const } Write-Host " Unique new permissions to add: $($uniqueConstants.Count)" -ForegroundColor Gray # Build new entries $newEntries = @() $addedCount = 0 foreach ($const in $uniqueConstants) { $enumName = Get-EnumName -Value $const.Value $description = Get-Description -Value $const.Value # Build the entry with proper indentation (8 spaces) # Don't add leading blank line for the first entry if ($addedCount -eq 0) { $entry = "/// `r`n" $entry += " /// $description.`r`n" $entry += " /// `r`n" $entry += " $enumName,`r`n" } else { $entry = "`r`n /// `r`n" $entry += " /// $description.`r`n" $entry += " /// `r`n" $entry += " $enumName,`r`n" } $newEntries += $entry $addedCount++ Write-Host " Added: $enumName" -ForegroundColor Green } if ($newEntries.Count -eq 0) { Write-Host "No new permissions to add." -ForegroundColor Gray return $true } # Insert new entries before the marker $markerIndex = $content.IndexOf($marker) $beforeMarker = $content.Substring(0, $markerIndex) $afterMarker = $content.Substring($markerIndex) $newContent = $beforeMarker + ($newEntries -join "") + "`r`n " + $afterMarker Set-Content -Path $PermissionIdPath -Value $newContent -NoNewline -Encoding UTF8 $skippedCount = $Constants.Count - $addedCount Write-Host " $addedCount new permissions added, $skippedCount skipped." -ForegroundColor Green return $true } # Function to replace references in all files function Replace-RightsReferences { param( [string]$BackendPath, [hashtable]$Replacements ) Write-Host "`nStep 3: Replacing Rights constant references..." -ForegroundColor Yellow # Merge BiaRights replacements with Rights replacements $allReplacements = $Replacements.Clone() foreach ($key in $biaRightsReplacements.Keys) { $allReplacements[$key] = $biaRightsReplacements[$key] } # Find all .cs files (except Rights.cs and in bin/obj) $csFiles = Get-ChildItem -Path $BackendPath -Filter "*.cs" -Recurse | Where-Object { $_.FullName -notmatch '\\bin\\' -and $_.FullName -notmatch '\\obj\\' -and $_.Name -ne 'Rights.cs' } Write-Host " Analyzing $($csFiles.Count) .cs files..." -ForegroundColor Gray Write-Host " Processing $($allReplacements.Count) replacement patterns ($($Replacements.Count) from Rights.cs + $($biaRightsReplacements.Count) from BiaRights)..." -ForegroundColor Gray # Sort replacements by key length (descending) to avoid partial matches # e.g., replace "Rights.Users.ListAccess" before "Rights.Users.List" $sortedReplacements = $allReplacements.GetEnumerator() | Sort-Object { $_.Key.Length } -Descending $totalReplacements = 0 $filesModified = 0 foreach ($file in $csFiles) { $content = Get-Content $file.FullName -Raw $originalContent = $content $fileReplacements = 0 # Apply all replacements from the merged dictionary (sorted by length) foreach ($replacement in $sortedReplacements) { $oldRef = $replacement.Key $newRef = $replacement.Value $escapedOldRef = [regex]::Escape($oldRef) if ($content -match $escapedOldRef) { $content = $content -replace $escapedOldRef, $newRef $matchCount = ([regex]::Matches($originalContent, $escapedOldRef)).Count $fileReplacements += $matchCount } } if ($content -ne $originalContent) { Set-Content -Path $file.FullName -Value $content -NoNewline -Encoding UTF8 $totalReplacements += $fileReplacements $filesModified++ Write-Host " Modified: $($file.Name) ($fileReplacements replacements)" -ForegroundColor Green } } Write-Host " Total: $totalReplacements replacements in $filesModified files." -ForegroundColor Green return $totalReplacements } # Main function function Start-Migration { param([string]$BackendPath) # Verify that the path exists if (-not (Test-Path $BackendPath)) { Write-Host "ERROR: The path $BackendPath does not exist." -ForegroundColor Red return } # Search for Rights.cs file $rightsFile = Get-ChildItem -Path $BackendPath -Filter "Rights.cs" -Recurse | Where-Object { $_.FullName -notmatch '\\bin\\' -and $_.FullName -notmatch '\\obj\\' } | Select-Object -First 1 if (-not $rightsFile) { Write-Host "ERROR: Rights.cs file not found in $BackendPath" -ForegroundColor Red return } Write-Host "Rights.cs file found: $($rightsFile.FullName)" -ForegroundColor Gray # Search for PermissionId.cs file $permissionIdFile = Get-ChildItem -Path $BackendPath -Filter "PermissionId.cs" -Recurse | Where-Object { $_.FullName -notmatch '\\bin\\' -and $_.FullName -notmatch '\\obj\\' } | Select-Object -First 1 if (-not $permissionIdFile) { Write-Host "ERROR: PermissionId.cs file not found in $BackendPath" -ForegroundColor Red return } Write-Host "PermissionId.cs file found: $($permissionIdFile.FullName)" -ForegroundColor Gray # Step 1: Extract constants and build replacement dictionary $result = Get-RightsConstants -RightsFilePath $rightsFile.FullName $constants = $result.Constants $replacements = $result.Replacements if ($constants.Count -eq 0) { Write-Host "ERROR: No constants found in Rights.cs" -ForegroundColor Red return } # Step 2: Add permissions $success = Add-PermissionsToEnum -PermissionIdPath $permissionIdFile.FullName -Constants $constants if (-not $success) { Write-Host "ERROR while adding permissions. Stopping script." -ForegroundColor Red return } # Step 3: Replace references using the replacement dictionary $replacementCount = Replace-RightsReferences -BackendPath $BackendPath -Replacements $replacements # Step 4: Delete Rights.cs Write-Host "`nStep 4: Deleting Rights.cs file..." -ForegroundColor Yellow try { Remove-Item -Path $rightsFile.FullName -Force Write-Host " Rights.cs file successfully deleted." -ForegroundColor Green } catch { Write-Host " ERROR while deleting Rights.cs: $_" -ForegroundColor Red } Write-Host "`n=== Migration completed successfully ===" -ForegroundColor Cyan Write-Host "Summary:" -ForegroundColor White Write-Host " - $($constants.Count) constants migrated" -ForegroundColor White Write-Host " - $replacementCount references updated" -ForegroundColor White Write-Host " - Rights.cs deleted" -ForegroundColor White } # Execution Start-Migration -BackendPath $BackendPath