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
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
}
</div>
@if (assignment.isInherited) {
<div class="text-primary d-flex gap-2">
<div class="text-primary d-flex gap-1 small">
<i class="bi bi-info-circle" [ngbTooltip]="'Portal.RbacManagement.InheritedTooltip' | translate"></i>
<span translate="Portal.RbacManagement.Inherited"></span>
<a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@
<i class="bi bi-person" [ngbTooltip]="'Portal.RbacManagement.PrincipalKind.User' | translate"></i>
}
}
<!-- TODO: Resolve ApiKey/User name -->
<span class="ms-1">{{ principal.principalId }}</span>
<span class="ms-2">{{ displayName$ | async }}</span>
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import { Component, Input } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { PrincipalDto, PrincipalKind } from '../../../api';
import { PrincipalsService } from '../../../api/services/principals.service';
import { catchError, Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';

@Component({
selector: 'tp-rbac-principal',
standalone: false,
templateUrl: './rbac-principal.component.html'
})
export class RbacPrincipalComponent {
export class RbacPrincipalComponent implements OnInit {
protected readonly PrincipalKind = PrincipalKind;

protected displayName$?: Observable<string>;

@Input()
public principal!: PrincipalDto;

constructor(private readonly principalsService: PrincipalsService) {}

public ngOnInit(): void {
this.displayName$ = this.principalsService
.getPrincipalName({
principalKind: this.principal.kind,
principalId: this.principal.principalId
})
.pipe(
map((result) => result.name),
catchError(() => of(this.principal.principalId))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using Turnierplan.Core.ApiKey;
using Turnierplan.Core.RoleAssignment;
using Turnierplan.Core.User;

namespace Turnierplan.App.Endpoints.Principals;

internal sealed class GetPrincipalNameEndpoint : EndpointBase<GetPrincipalNameEndpoint.GetPrincipalNameEndpointResponse>
{
protected override HttpMethod Method => HttpMethod.Get;

protected override string Route => "/api/principals/name";

protected override Delegate Handler => Handle;

private static async Task<IResult> Handle(
[FromQuery] PrincipalKind principalKind,
[FromQuery] Guid principalId,
IApiKeyRepository apiKeyRepository,
IUserRepository userRepository)
{
string? name;

switch (principalKind)
{
case PrincipalKind.ApiKey:
var apiKey = await apiKeyRepository.GetByPrincipalIdAsync(principalId).ConfigureAwait(false);
name = apiKey?.Name;
break;
case PrincipalKind.User:
var user = await userRepository.GetByPrincipalIdAsync(principalId).ConfigureAwait(false);
name = user?.Name;
break;
default:
return Results.BadRequest("Invalid principal kind specified.");
}

return name is not null
? Results.Ok(new GetPrincipalNameEndpointResponse(name))
: Results.NotFound();
}

public sealed record GetPrincipalNameEndpointResponse(string Name);
}
2 changes: 2 additions & 0 deletions src/Turnierplan.Core/ApiKey/IApiKeyRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ namespace Turnierplan.Core.ApiKey;

public interface IApiKeyRepository : IRepositoryWithPublicId<ApiKey, long>
{
Task<ApiKey?> GetByPrincipalIdAsync(Guid id);

Task<List<ApiKeyRequest>> GetRequestsInTimeRange(ApiKey apiKey, DateTime start, DateTime end);
}
2 changes: 2 additions & 0 deletions src/Turnierplan.Core/User/IUserRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ public interface IUserRepository : IRepository<User, Guid>

Task<User?> GetByIdAsync(Guid id);

Task<User?> GetByPrincipalIdAsync(Guid id);

Task<User?> GetByEmailAsync(string email);
}
5 changes: 5 additions & 0 deletions src/Turnierplan.Dal/Repositories/ApiKeyRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public ApiKeyRepository(TurnierplanContext context)
.FirstOrDefaultAsync();
}

public Task<ApiKey?> GetByPrincipalIdAsync(Guid id)
{
return DbSet.Where(x => x.PrincipalId == id).FirstOrDefaultAsync();
}

public Task<List<ApiKeyRequest>> GetRequestsInTimeRange(ApiKey apiKey, DateTime start, DateTime end)
{
return _requests.Where(x => x.ApiKey == apiKey && x.Timestamp >= start && x.Timestamp <= end)
Expand Down
5 changes: 5 additions & 0 deletions src/Turnierplan.Dal/Repositories/UserRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ public Task<List<User>> GetAllUsers()
return DbSet.Where(x => x.Id.Equals(id)).FirstOrDefaultAsync();
}

public Task<User?> GetByPrincipalIdAsync(Guid id)
{
return DbSet.Where(x => x.PrincipalId == id).FirstOrDefaultAsync();
}

public Task<User?> GetByEmailAsync(string email)
{
var normalizedEMail = User.NormalizeEmail(email);
Expand Down
Loading