Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { filter } from 'rxjs/operators';
import { ResourcePlannerHeaderDto } from '../../../api/models/resource-planner-header-dto';
import { getResourcePlanners } from '../../../api/fn/resource-planners/get-resource-planners';
import { environment } from '../../../../environments/environment';

@Component({
templateUrl: './view-organization.component.html',
Expand Down Expand Up @@ -131,11 +132,15 @@ export class ViewOrganizationComponent implements OnInit, OnDestroy {
title: 'Portal.ViewOrganization.Pages.TournamentPlanners',
icon: 'bi-ticket-perforated'
},
{
id: ViewOrganizationComponent.resourcePlannersPageId,
title: 'Portal.ViewOrganization.Pages.ResourcePlanners',
icon: 'bi-file-earmark-spreadsheet'
},
...(environment.featureFlags.resourcePlanners
? [
{
id: ViewOrganizationComponent.resourcePlannersPageId,
title: 'Portal.ViewOrganization.Pages.ResourcePlanners',
icon: 'bi-file-earmark-spreadsheet'
}
]
: []),
{
id: ViewOrganizationComponent.imagesPageId,
title: 'Portal.ViewOrganization.Pages.Images',
Expand Down
27 changes: 19 additions & 8 deletions src/Turnierplan.App/Client/src/app/portal/portal.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ViewVenueComponent } from './pages/view-venue/view-venue.component';
import { UploadImageComponent } from './pages/upload-image/upload-image.component';
import { CreateResourcePlannerComponent } from './pages/create-resource-planner/create-resource-planner.component';
import { ViewResourcePlannerComponent } from './pages/view-resource-planner/view-resource-planner.component';
import { environment } from '../../environments/environment';

export const portalRoutes: Routes = [
{
Expand Down Expand Up @@ -63,10 +64,15 @@ export const portalRoutes: Routes = [
return `organization/${data.params['id']}/create/tournament-planner`;
}
},
{
path: 'organization/:id/create/resource-planner',
component: CreateResourcePlannerComponent
},
...(environment.featureFlags.resourcePlanners
? [
{
path: 'organization/:id/create/resource-planner',
component: CreateResourcePlannerComponent
}
]
: []),

{
path: 'organization/:id/create/tournament-planner',
component: CreateTournamentPlannerComponent
Expand All @@ -85,10 +91,15 @@ export const portalRoutes: Routes = [
return `tournament-planner/${data.params['id']}`;
}
},
{
path: 'resource-planner/:id',
component: ViewResourcePlannerComponent
},
...(environment.featureFlags.resourcePlanners
? [
{
path: 'resource-planner/:id',
component: ViewResourcePlannerComponent
}
]
: []),

{
path: 'tournament-planner/:id',
component: ViewTournamentPlannerComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
version: '1.0.0',
originOverwrite: undefined,
includeE2EData: true,
doUpdatesCheck: false
doUpdatesCheck: false,
featureFlags: {
resourcePlanners: false
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
version: '2026.3.0',
originOverwrite: undefined,
includeE2EData: false,
doUpdatesCheck: true
doUpdatesCheck: true,
featureFlags: {
resourcePlanners: false
}
};
5 changes: 4 additions & 1 deletion src/Turnierplan.App/Client/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ export const environment = {
version: '0.0.0',
originOverwrite: 'http://localhost:45000',
includeE2EData: true,
doUpdatesCheck: false
doUpdatesCheck: false,
featureFlags: {
resourcePlanners: true
}
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net;
using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Turnierplan.App.Extensions;
Expand All @@ -18,6 +19,7 @@ internal sealed class CreateResourcePlannerEndpoint : EndpointBase<ResourcePlann

protected override Delegate Handler => Handle;

#if TP_RESOURCE_PLANNER
private static async Task<IResult> Handle(
[FromBody] CreateResourcePlannerEndpointRequest request,
IOrganizationRepository organizationRepository,
Expand Down Expand Up @@ -52,6 +54,12 @@ private static async Task<IResult> Handle(

return Results.Ok(mapper.Map<ResourcePlannerDto>(resourcePlanner));
}
#else
private static IResult Handle([FromBody] CreateResourcePlannerEndpointRequest request)
{
return Results.StatusCode((int)HttpStatusCode.NotImplemented);
}
#endif

public sealed record CreateResourcePlannerEndpointRequest
{
Expand All @@ -60,6 +68,7 @@ public sealed record CreateResourcePlannerEndpointRequest
public required string Name { get; init; }
}

#if TP_RESOURCE_PLANNER
internal sealed class Validator : AbstractValidator<CreateResourcePlannerEndpointRequest>
{
public static readonly Validator Instance = new();
Expand All @@ -70,4 +79,5 @@ private Validator()
.NotEmpty();
}
}
#endif
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Turnierplan.App.Mapping;
using Turnierplan.App.Models;
Expand All @@ -15,6 +16,7 @@ internal sealed class GetResourcePlannerEndpoint : EndpointBase<ResourcePlannerD

protected override Delegate Handler => Handle;

#if TP_RESOURCE_PLANNER
private static async Task<IResult> Handle(
[FromRoute] PublicId id,
IResourcePlannerRepository repository,
Expand All @@ -37,4 +39,10 @@ private static async Task<IResult> Handle(

return Results.Ok(mapper.Map<ResourcePlannerDto>(resourcePlanner));
}
#else
private static IResult Handle([FromRoute] PublicId id)
{
return Results.StatusCode((int)HttpStatusCode.NotImplemented);
}
#endif
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Turnierplan.App.Mapping;
using Turnierplan.App.Models;
Expand All @@ -15,6 +16,7 @@ internal sealed class GetResourcePlannersEndpoint : EndpointBase<IEnumerable<Res

protected override Delegate Handler => Handle;

#if TP_RESOURCE_PLANNER
private static async Task<IResult> Handle(
[FromQuery] PublicId organizationId,
IOrganizationRepository organizationRepository,
Expand All @@ -35,4 +37,10 @@ private static async Task<IResult> Handle(

return Results.Ok(mapper.MapCollection<ResourcePlannerHeaderDto>(organization.ResourcePlanners));
}
#else
private static IResult Handle([FromQuery] PublicId organizationId)
{
return Results.StatusCode((int)HttpStatusCode.NotImplemented);
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
using Turnierplan.Core.Image;
using Turnierplan.Core.Organization;
using Turnierplan.Core.PublicId;
#if TP_RESOURCE_PLANNER
using Turnierplan.Core.ResourcePlanner;
#endif
using Turnierplan.Core.RoleAssignment;
using Turnierplan.Core.Tournament;
using Turnierplan.Core.TournamentPlanner;
Expand Down Expand Up @@ -52,7 +54,9 @@ private static async Task<IResult> Handle(
"Folder" => CreateRoleAssignmentAsync<Folder>(request, serviceProvider, accessValidator, mapper, targetId, cancellationToken),
"Image" => CreateRoleAssignmentAsync<Image>(request, serviceProvider, accessValidator, mapper, targetId, cancellationToken),
"Organization" => CreateRoleAssignmentAsync<Organization>(request, serviceProvider, accessValidator, mapper, targetId, cancellationToken),
#if TP_RESOURCE_PLANNER
"ResourcePlanner" => CreateRoleAssignmentAsync<ResourcePlanner>(request, serviceProvider, accessValidator, mapper, targetId, cancellationToken),
#endif
"Tournament" => CreateRoleAssignmentAsync<Tournament>(request, serviceProvider, accessValidator, mapper, targetId, cancellationToken),
"TournamentPlanner" => CreateRoleAssignmentAsync<TournamentPlanner>(request, serviceProvider, accessValidator, mapper, targetId, cancellationToken),
"Venue" => CreateRoleAssignmentAsync<Venue>(request, serviceProvider, accessValidator, mapper, targetId, cancellationToken),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
using Turnierplan.Core.Image;
using Turnierplan.Core.Organization;
using Turnierplan.Core.PublicId;
#if TP_RESOURCE_PLANNER
using Turnierplan.Core.ResourcePlanner;
#endif
using Turnierplan.Core.RoleAssignment;
using Turnierplan.Core.Tournament;
using Turnierplan.Core.TournamentPlanner;
Expand Down Expand Up @@ -47,7 +49,9 @@ private static async Task<IResult> Handle(
"Folder" => DeleteRoleAssignmentAsync<Folder>(serviceProvider, accessValidator, targetId, roleAssignmentGuid, cancellationToken),
"Image" => DeleteRoleAssignmentAsync<Image>(serviceProvider, accessValidator, targetId, roleAssignmentGuid, cancellationToken),
"Organization" => DeleteRoleAssignmentAsync<Organization>(serviceProvider, accessValidator, targetId, roleAssignmentGuid, cancellationToken),
#if TP_RESOURCE_PLANNER
"ResourcePlanner" => DeleteRoleAssignmentAsync<ResourcePlanner>(serviceProvider, accessValidator, targetId, roleAssignmentGuid, cancellationToken),
#endif
"Tournament" => DeleteRoleAssignmentAsync<Tournament>(serviceProvider, accessValidator, targetId, roleAssignmentGuid, cancellationToken),
"TournamentPlanner" => DeleteRoleAssignmentAsync<TournamentPlanner>(serviceProvider, accessValidator, targetId, roleAssignmentGuid, cancellationToken),
"Venue" => DeleteRoleAssignmentAsync<Venue>(serviceProvider, accessValidator, targetId, roleAssignmentGuid, cancellationToken),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
using Turnierplan.Core.Image;
using Turnierplan.Core.Organization;
using Turnierplan.Core.PublicId;
#if TP_RESOURCE_PLANNER
using Turnierplan.Core.ResourcePlanner;
#endif
using Turnierplan.Core.Tournament;
using Turnierplan.Core.TournamentPlanner;
using Turnierplan.Core.Venue;
Expand Down Expand Up @@ -42,7 +44,9 @@ private static async Task<IResult> Handle(
"Folder" => GetRoleAssignmentsAsync<Folder>(serviceProvider, accessValidator, mapper, targetId),
"Image" => GetRoleAssignmentsAsync<Image>(serviceProvider, accessValidator, mapper, targetId),
"Organization" => GetRoleAssignmentsAsync<Organization>(serviceProvider, accessValidator, mapper, targetId),
#if TP_RESOURCE_PLANNER
"ResourcePlanner" => GetRoleAssignmentsAsync<ResourcePlanner>(serviceProvider, accessValidator, mapper, targetId),
#endif
"Tournament" => GetRoleAssignmentsAsync<Tournament>(serviceProvider, accessValidator, mapper, targetId),
"TournamentPlanner" => GetRoleAssignmentsAsync<TournamentPlanner>(serviceProvider, accessValidator, mapper, targetId),
"Venue" => GetRoleAssignmentsAsync<Venue>(serviceProvider, accessValidator, mapper, targetId),
Expand Down
4 changes: 4 additions & 0 deletions src/Turnierplan.App/Helpers/RbacScopeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public static bool TryParseScopeId(string scopeId, [NotNullWhen(true)] out strin
return true;
}

#if TP_RESOURCE_PLANNER
[GeneratedRegex("^(?<TypeName>ApiKey|Folder|Image|Organization|ResourcePlanner|Tournament|TournamentPlanner|Venue):(?<ObjectId>[A-Za-z0-9_-]{11})$")]
#else
[GeneratedRegex("^(?<TypeName>ApiKey|Folder|Image|Organization|Tournament|TournamentPlanner|Venue):(?<ObjectId>[A-Za-z0-9_-]{11})$")]
#endif
public static partial Regex ScopeIdRegex();
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#if TP_RESOURCE_PLANNER

using Turnierplan.App.Models;
using Turnierplan.Core.ResourcePlanner;

Expand All @@ -15,3 +17,5 @@ protected override ResourcePlannerHeaderDto Map(IMapper mapper, MappingContext c
};
}
}

#endif
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#if TP_RESOURCE_PLANNER

using Turnierplan.App.Helpers;
using Turnierplan.App.Models;
using Turnierplan.Core.ResourcePlanner;
Expand Down Expand Up @@ -65,3 +67,5 @@ protected override ResourcePlannerDto Map(IMapper mapper, MappingContext context
};
}
}

#endif
6 changes: 6 additions & 0 deletions src/Turnierplan.App/Security/AccessValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using Turnierplan.Core.Folder;
using Turnierplan.Core.Image;
using Turnierplan.Core.PublicId;
#if TP_RESOURCE_PLANNER
using Turnierplan.Core.ResourcePlanner;
#endif
using Turnierplan.Core.RoleAssignment;
using Turnierplan.Core.Tournament;
using Turnierplan.Core.TournamentPlanner;
Expand Down Expand Up @@ -104,7 +106,9 @@ internal static bool IsActionAllowed<T>(IEntityWithRoleAssignments<T> target, Ac
ApiKey apiKey => IsActionAllowed(apiKey.Organization, action, principal),
Image image => IsActionAllowed(image.Organization, action, principal),
Folder folder => IsActionAllowed(folder.Organization, action, principal),
#if TP_RESOURCE_PLANNER
ResourcePlanner resourcePlanner => IsActionAllowed(resourcePlanner.Organization, action, principal),
#endif
TournamentPlanner tournamentPlanner => IsActionAllowed(tournamentPlanner.Organization, action, principal),
Tournament tournament => (tournament.Folder is not null && IsActionAllowed(tournament.Folder, action, principal)) || IsActionAllowed(tournament.Organization, action, principal),
Venue venue => IsActionAllowed(venue.Organization, action, principal),
Expand All @@ -128,9 +132,11 @@ internal static void AddAvailableRoles<T>(IEntityWithRoleAssignments<T> target,
case Folder folder:
AddAvailableRoles(folder.Organization, rolesList, principal);
break;
#if TP_RESOURCE_PLANNER
case ResourcePlanner resourcePlanner:
AddAvailableRoles(resourcePlanner.Organization, rolesList, principal);
break;
#endif
case TournamentPlanner tournamentPlanner:
AddAvailableRoles(tournamentPlanner.Organization, rolesList, principal);
break;
Expand Down
4 changes: 4 additions & 0 deletions src/Turnierplan.Core/Organization/Organization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public sealed class Organization : Entity<long>, IEntityWithRoleAssignments<Orga
internal readonly List<ApiKey.ApiKey> _apiKeys = [];
internal readonly List<Folder.Folder> _folders = [];
internal readonly List<Image.Image> _images = [];
#if TP_RESOURCE_PLANNER
internal readonly List<ResourcePlanner.ResourcePlanner> _resourcePlanners = [];
#endif
internal readonly List<TournamentPlanner.TournamentPlanner> _tournamentPlanners = [];
internal readonly List<Tournament.Tournament> _tournaments = [];
internal readonly List<Venue.Venue> _venues = [];
Expand Down Expand Up @@ -46,7 +48,9 @@ internal Organization(long id, PublicId.PublicId publicId, DateTime createdAt, s

public IReadOnlyList<Image.Image> Images => _images.AsReadOnly();

#if TP_RESOURCE_PLANNER
public IReadOnlyList<ResourcePlanner.ResourcePlanner> ResourcePlanners => _resourcePlanners.AsReadOnly();
#endif

public IReadOnlyList<TournamentPlanner.TournamentPlanner> TournamentPlanners => _tournamentPlanners.AsReadOnly();

Expand Down
4 changes: 4 additions & 0 deletions src/Turnierplan.Core/ResourcePlanner/Resource.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#if TP_RESOURCE_PLANNER

using Turnierplan.Core.Entity;
using Turnierplan.Core.Exceptions;

Expand Down Expand Up @@ -53,3 +55,5 @@ public string? Notes
}
}
}

#endif
4 changes: 4 additions & 0 deletions src/Turnierplan.Core/ResourcePlanner/ResourceAssignment.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#if TP_RESOURCE_PLANNER

namespace Turnierplan.Core.ResourcePlanner;

public sealed class ResourceAssignment
Expand All @@ -20,3 +22,5 @@ internal ResourceAssignment(ResourceGroup resourceGroup, Resource resource)

public ResourceAssignmentState State { get; set; }
}

#endif
4 changes: 4 additions & 0 deletions src/Turnierplan.Core/ResourcePlanner/ResourceGroup.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#if TP_RESOURCE_PLANNER

using Turnierplan.Core.Entity;
using Turnierplan.Core.Exceptions;

Expand Down Expand Up @@ -156,3 +158,5 @@ public void UnassignResource(ResourceAssignment assignment)
_resourceAssignments.Remove(assignment);
}
}

#endif
4 changes: 4 additions & 0 deletions src/Turnierplan.Core/ResourcePlanner/ResourcePlanner.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#if TP_RESOURCE_PLANNER

using Turnierplan.Core.Entity;
using Turnierplan.Core.RoleAssignment;

Expand Down Expand Up @@ -83,3 +85,5 @@ public void RemoveResourcePlannerView(ResourcePlannerView resourcePlannerView)
_resourcePlannerViews.Remove(resourcePlannerView);
}
}

#endif
Loading
Loading