Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions 4-Nine/Features/Administration/Users/View.razor
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,16 @@ else if (viewedUser == null)
else if (!canViewUser)
{
<div class="alert alert-danger">
<h4>Access Denied</h4>
<p>You don't have permission to view this user's account.</p>
@if (!string.IsNullOrEmpty(errorMessage))
{
<h4>Unable to Load User</h4>
<p>@errorMessage</p>
}
else
{
<h4>Access Denied</h4>
<p>You don't have permission to view this user's account.</p>
}
<a href="/admin/users" class="btn btn-primary">Back to User Management</a>
</div>
}
Expand Down Expand Up @@ -327,9 +335,15 @@ else

// Check permissions
var currentOrgId = await UserContext.GetActiveOrganizationIdAsync();
var currentUserRole = await OrganizationService.GetUserRoleForOrganizationAsync(currentUser.Id, currentOrgId.Value);
isCurrentUserAdmin = currentUserRole == ApplicationConstants.OrganizationRoles.Owner ||
currentUserRole == ApplicationConstants.OrganizationRoles.Administrator;
if (!currentOrgId.HasValue)
{
errorMessage = "Unable to determine current organization context.";
return;
}

var actingUserRole = await OrganizationService.GetUserRoleForOrganizationAsync(currentUser.Id, currentOrgId.Value);
isCurrentUserAdmin = actingUserRole == ApplicationConstants.OrganizationRoles.Owner ||
actingUserRole == ApplicationConstants.OrganizationRoles.Administrator;
isViewingOwnAccount = currentUser.Id == viewedUser.Id;

// Users can view their own account, admins can view any account in the same org
Expand All @@ -342,8 +356,8 @@ else
// Load user's organization role
var viewedUserRole = await OrganizationService.GetUserRoleForOrganizationAsync(viewedUser.Id, currentOrgId.Value);
userRoles = viewedUserRole != null ? new List<string> { viewedUserRole } : new List<string>();
currentUserRole = viewedUserRole ?? "No Role";
selectedRole = currentUserRole;
currentUserRole = viewedUserRole ?? "No role found";
selectedRole = viewedUserRole ?? string.Empty;
isLockedOut = await UserManager.IsLockedOutAsync(viewedUser);

// Load available roles for admins
Expand Down
30 changes: 19 additions & 11 deletions 4-Nine/Nine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.1" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.1" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.21" />
<PackageReference Include="QuestPDF" Version="2025.12.1" />
</ItemGroup>

Expand Down Expand Up @@ -103,7 +104,9 @@
Linux/macOS: npm's allow-scripts policy and extract-zip failures prevent automatic download,
so the cache (~/.cache/electron) is used directly via unzip.

Windows: PowerShell Expand-Archive extracts from %LOCALAPPDATA%\electron\Cache.
Windows: the zip is located with an item glob in %LOCALAPPDATA%\electron\Cache and extracted
with MSBuild's Unzip task. PowerShell is avoided because a Windows PowerShell 5.1 child
process can inherit a PowerShell 7 PSModulePath and fail in Expand-Archive.

First-time setup (no cache): the build emits a warning with exact steps to seed the cache.
-->
Expand Down Expand Up @@ -136,13 +139,16 @@
<Output TaskParameter="ConsoleOutput" PropertyName="_ElectronZipPath" />
</Exec>

<!-- Locate zip in cache (Windows) -->
<Exec Command="powershell -NoProfile -Command &quot;(Get-ChildItem -Path '$(_ElectronCacheDir)' -Filter '$(_ElectronZipName)' -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1).FullName&quot;"
ConsoleToMSBuild="true"
EchoOff="true"
Condition="!Exists('$(_ElectronBinaryPath)') And $([MSBuild]::IsOSPlatform('Windows'))">
<Output TaskParameter="ConsoleOutput" PropertyName="_ElectronZipPath" />
</Exec>
<!-- Locate zip in cache (Windows) with an item glob; no shell involved -->
<ItemGroup Condition="!Exists('$(_ElectronBinaryPath)') And $([MSBuild]::IsOSPlatform('Windows'))">
<_ElectronZipCandidate Include="$(_ElectronCacheDir)\**\$(_ElectronZipName)" />
</ItemGroup>

<!-- Keep only the first match; the cache can hold the same zip in several folders -->
<PropertyGroup Condition="!Exists('$(_ElectronBinaryPath)') And $([MSBuild]::IsOSPlatform('Windows'))">
<_ElectronZipPath>@(_ElectronZipCandidate)</_ElectronZipPath>
<_ElectronZipPath Condition="$(_ElectronZipPath.Contains(';'))">$(_ElectronZipPath.Substring(0, $(_ElectronZipPath.IndexOf(';'))))</_ElectronZipPath>
</PropertyGroup>

<Message Text="[ElectronRestore] Binary missing — restoring from cache: $(_ElectronZipPath)"
Importance="high"
Expand All @@ -152,9 +158,11 @@
<Exec Command="rm -rf &quot;$(_ElectronDistPath)&quot; &amp;&amp; unzip -q &quot;$(_ElectronZipPath)&quot; -d &quot;$(_ElectronDistPath)&quot; &amp;&amp; chmod -R a+x &quot;$(_ElectronDistPath)&quot;"
Condition="!Exists('$(_ElectronBinaryPath)') And '$(_ElectronZipPath)' != '' And $([MSBuild]::IsOSPlatform('Linux'))" />

<!-- Extract (Windows) -->
<Exec Command="powershell -NoProfile -Command &quot;if (Test-Path '$(_ElectronDistPath)') { Remove-Item -Path '$(_ElectronDistPath)' -Recurse -Force }; Expand-Archive -Path '$(_ElectronZipPath)' -DestinationPath '$(_ElectronDistPath)' -Force&quot;"
Condition="!Exists('$(_ElectronBinaryPath)') And '$(_ElectronZipPath)' != '' And $([MSBuild]::IsOSPlatform('Windows'))" />
<!-- Extract (Windows) — overwrites any partial dist without deleting it first -->
<Unzip SourceFiles="$(_ElectronZipPath)"
DestinationFolder="$(_ElectronDistPath)"
OverwriteReadOnlyFiles="true"
Condition="!Exists('$(_ElectronBinaryPath)') And '$(_ElectronZipPath)' != '' And $([MSBuild]::IsOSPlatform('Windows'))" />

<!--
No cache found — first-time setup. Instruct the developer to run npm install once
Expand Down
1 change: 1 addition & 0 deletions 6-Tests/Nine.Shared.UI.Tests/Nine.Shared.UI.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AngleSharp" Version="1.5.0" />
<PackageReference Include="bunit" Version="2.7.2" />
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="FluentAssertions" Version="8.8.0" />
Expand Down
Loading