Skip to content

Commit f841083

Browse files
authored
Переработать загрузку списка проектов, разрешить копировать закрытые проекты (#3374)
1 parent 469073b commit f841083

File tree

13 files changed

+82
-35
lines changed

13 files changed

+82
-35
lines changed

src/JoinRpg.Blazor.Client/ApiClients/ProjectClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ namespace JoinRpg.Blazor.Client.ApiClients;
55

66
public class ProjectListClient(HttpClient httpClient) : IProjectListClient
77
{
8-
public async Task<ProjectDto[]> GetProjectsWithMyMasterAccess()
8+
public async Task<ProjectDto[]> GetProjects(ProjectSelectionCriteria projectSelectionCriteria)
99
{
10-
return await httpClient.GetFromJsonAsync<ProjectDto[]>($"webapi/projects/GetProjectsWithMyMasterAccess") ?? throw new Exception("Couldn't get result from server");
10+
return await httpClient.GetFromJsonAsync<ProjectDto[]>($"webapi/projects/GetProjects?criteria={projectSelectionCriteria}") ?? throw new Exception("Couldn't get result from server");
1111
}
1212
}
1313

src/JoinRpg.Dal.Impl/Repositories/ProjectPredicates.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System.Linq.Expressions;
2+
using JoinRpg.Data.Interfaces;
3+
using JoinRpg.Data.Interfaces.Claims;
24
using JoinRpg.DataModel;
35
using JoinRpg.PrimitiveTypes;
46
using JoinRpg.PrimitiveTypes.ProjectMetadata;
7+
using LinqKit;
58

69
namespace JoinRpg.Dal.Impl.Repositories;
710

@@ -20,6 +23,36 @@ public static Expression<Func<Project, bool>> Status(ProjectLifecycleStatus stat
2023

2124
public static Expression<Func<Project, bool>> Active() => project => project.Active;
2225

23-
public static Expression<Func<Project, bool>> MyProjectPredicate(UserIdentification userInfoId)
26+
public static Expression<Func<Project, bool>> MasterAccess(UserIdentification userInfoId)
2427
=> project => project.ProjectAcls.Any(projectAcl => projectAcl.UserId == userInfoId.Value);
28+
29+
public static Expression<Func<Project, bool>> HasActiveClaim(UserIdentification userInfoId)
30+
{
31+
var claimPredicate = ClaimPredicates.GetClaimStatusPredicate(ClaimStatusSpec.Active);
32+
return project => project.Claims.Where(c => c.PlayerUserId == userInfoId.Value).Any(claimPredicate.Compile());
33+
}
34+
35+
public static Expression<Func<Project, bool>> BySpecification(UserIdentification userInfoId, ProjectListSpecification projectListSpecification)
36+
{
37+
var predicate = PredicateBuilder.New<Project>();
38+
if (!projectListSpecification.LoadArchived)
39+
{
40+
predicate = predicate.And(p => p.Active);
41+
}
42+
43+
predicate = projectListSpecification.Criteria switch
44+
{
45+
ProjectListCriteria.MasterAccess => predicate.And(MasterAccess(userInfoId)),
46+
ProjectListCriteria.MasterOrActiveClaim => predicate.And(PredicateBuilder.New<Project>().Or(HasActiveClaim(userInfoId)).Or(MasterAccess(userInfoId))),
47+
ProjectListCriteria.ForCloning => predicate.And(ForCloning(userInfoId)),
48+
ProjectListCriteria.HasSchedule => predicate.And(project => project.Details.ScheduleEnabled),
49+
_ => throw new NotImplementedException(),
50+
};
51+
return predicate;
52+
}
53+
54+
private static Expression<Func<Project, bool>> ForCloning(UserIdentification userInfoId)
55+
{
56+
return project => MasterAccess(userInfoId).Compile()(project);
57+
}
2558
}

src/JoinRpg.Dal.Impl/Repositories/ProjectRepository.cs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,6 @@ public async Task<IReadOnlyCollection<ProjectWithClaimCount>> GetAllProjectsWith
5959
private IQueryable<Project> ActiveProjects => AllProjects.Where(project => project.Active);
6060
private IQueryable<Project> AllProjects => Ctx.ProjectsSet.Include(p => p.ProjectAcls);
6161

62-
public async Task<IEnumerable<Project>> GetMyActiveProjectsAsync(int userInfoId) => await
63-
ActiveProjects.Where(ProjectPredicates.MyProjectPredicate(new(userInfoId))).ToListAsync();
64-
65-
public async Task<IEnumerable<Project>> GetActiveProjectsWithSchedule()
66-
=> await ActiveProjects.Where(project => project.Details.ScheduleEnabled)
67-
.ToListAsync();
68-
6962
public Task<Project> GetProjectAsync(int project) => AllProjects.SingleOrDefaultAsync(p => p.ProjectId == project);
7063

7164
public Task<Project> GetProjectWithDetailsAsync(int project)
@@ -430,20 +423,19 @@ async Task<ProjectMastersListInfo> IProjectMetadataRepository.GetMastersList(Pro
430423

431424
return new ProjectMastersListInfo(projectId, project.ProjectName, masters.ToArray());
432425
}
433-
434-
async Task<ProjectHeaderDto[]> IProjectRepository.GetMyProjects(UserIdentification userIdentification)
426+
async Task<ProjectHeaderDto[]> IProjectRepository.GetProjectsBySpecification(UserIdentification userIdentification, ProjectListSpecification projectListSpecification)
435427
{
436-
var predicate = ClaimPredicates.GetClaimStatusPredicate(ClaimStatusSpec.Active);
437-
var query = from project in ActiveProjects.AsExpandable()
438-
let master = project.ProjectAcls.Any(a => a.UserId == userIdentification.Value)
439-
let claims = project.Claims.Where(c => c.PlayerUserId == userIdentification.Value).Any(predicate.Compile())
440-
where master || claims
428+
var filterPredicate = ProjectPredicates.BySpecification(userIdentification, projectListSpecification);
429+
var masterPredicate = ProjectPredicates.MasterAccess(userIdentification);
430+
var claimPredicate = ProjectPredicates.HasActiveClaim(userIdentification);
431+
var query = from project in AllProjects.AsExpandable()
432+
where filterPredicate.Compile()(project)
441433
select new
442434
{
443435
project.ProjectId,
444436
project.ProjectName,
445-
IAmMaster = master,
446-
HasActiveClaims = claims,
437+
IAmMaster = masterPredicate.Compile()(project),
438+
HasActiveClaims = claimPredicate.Compile()(project),
447439
};
448440

449441
var result = await query.ToListAsync();

src/JoinRpg.Data.Interfaces/IProjectRepository.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ Task<IReadOnlyCollection<ProjectWithClaimCount>> GetArchivedProjectsWithClaimCou
1212

1313
Task<IReadOnlyCollection<ProjectWithClaimCount>> GetAllProjectsWithClaimCount(int? userId);
1414

15-
Task<IEnumerable<Project>> GetMyActiveProjectsAsync(int userInfoId);
16-
17-
Task<IEnumerable<Project>> GetActiveProjectsWithSchedule();
1815
Task<Project> GetProjectAsync(int project);
1916
Task<Project> GetProjectWithDetailsAsync(int project);
2017
Task<Project?> GetProjectWithFieldsAsync(int project);
@@ -55,11 +52,21 @@ Task<ProjectFieldDropdownValue> GetFieldValue(ProjectFieldIdentification project
5552
/// <returns></returns>
5653
Task<IReadOnlyCollection<ProjectWithUpdateDateDto>> GetStaleProjects(DateTime inActiveSince);
5754

58-
Task<ProjectHeaderDto[]> GetMyProjects(UserIdentification userIdentification);
55+
Task<ProjectHeaderDto[]> GetProjectsBySpecification(UserIdentification userIdentification, ProjectListSpecification projectListSpecification);
5956

6057
Task<CharacterGroupHeaderDto[]> LoadDirectChildGroupHeaders(CharacterGroupIdentification characterGroupId);
6158
}
6259

60+
public record ProjectListSpecification(ProjectListCriteria Criteria, bool LoadArchived)
61+
{
62+
public static ProjectListSpecification MyActiveProjects { get; } = new ProjectListSpecification(ProjectListCriteria.MasterOrActiveClaim, LoadArchived: false);
63+
public static ProjectListSpecification ForCloning { get; } = new ProjectListSpecification(ProjectListCriteria.ForCloning, LoadArchived: true);
64+
public static ProjectListSpecification ActiveWithMyMasterAccess { get; } = new ProjectListSpecification(ProjectListCriteria.MasterAccess, LoadArchived: false);
65+
public static ProjectListSpecification ActiveProjectsWithSchedule { get; } = new ProjectListSpecification(ProjectListCriteria.HasSchedule, LoadArchived: false);
66+
}
67+
68+
public enum ProjectListCriteria { MasterAccess, MasterOrActiveClaim, ForCloning, HasSchedule };
69+
6370
public record ProjectHeaderDto(ProjectIdentification ProjectId, string ProjectName, bool IAmMaster, bool HasActiveClaims) : ILinkableWithName
6471
{
6572
string ILinkableWithName.Name => ProjectName;

src/JoinRpg.Portal/Controllers/WebApi/ProjectListController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ namespace JoinRpg.Portal.Controllers.WebApi;
88
public class ProjectListController(IProjectListClient client) : ControllerBase
99
{
1010
[HttpGet]
11-
public async Task<ProjectDto[]> GetProjectsWithMyMasterAccess() => await client.GetProjectsWithMyMasterAccess();
11+
public async Task<ProjectDto[]> GetProjects(ProjectSelectionCriteria criteria) => await client.GetProjects(criteria);
1212
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
using JoinRpg.Data.Interfaces;
2+
using JoinRpg.Interfaces;
23
using JoinRpg.XGameApi.Contract;
34
using Microsoft.AspNetCore.Authorization;
45
using Microsoft.AspNetCore.Mvc;
56

67
namespace JoinRpg.Portal.Controllers.XGameApi;
78

89
[Route("x-game-api/schedule")]
9-
public class GlobalScheduleController(IProjectRepository projectRepository) : XGameApiController
10+
public class GlobalScheduleController(IProjectRepository projectRepository, ICurrentUserAccessor currentUserAccessor) : XGameApiController
1011
{
1112
/// <summary>
1213
/// All active projects with schedules
1314
/// </summary>
1415
[HttpGet, Authorize, Route("projects/active")]
1516
public async Task<IEnumerable<ProjectHeader>> GetActiveProjects()
1617
{
17-
return (await projectRepository.GetActiveProjectsWithSchedule())
18+
return (await projectRepository.GetProjectsBySpecification(currentUserAccessor.UserIdentification, ProjectListSpecification.ActiveProjectsWithSchedule))
1819
.Select(p => new ProjectHeader { ProjectId = p.ProjectId, ProjectName = p.ProjectName });
1920
}
2021
}

src/JoinRpg.Portal/Controllers/XGameApi/MyProfileController.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ public class MyProfileController(IProjectRepository projectRepository, ICurrentU
1616
[HttpGet, Authorize, Route("projects/active")]
1717
public async Task<IEnumerable<ProjectHeader>> GetActiveProjects()
1818
{
19-
var userId = currentUserAccessor.UserId;
20-
return (await projectRepository.GetMyActiveProjectsAsync(userId)).Select(
19+
return (await projectRepository.GetProjectsBySpecification(currentUserAccessor.UserIdentification, ProjectListSpecification.MyActiveProjects)).Select(
2120
p => new ProjectHeader { ProjectId = p.ProjectId, ProjectName = p.ProjectName });
2221
}
2322
}

src/JoinRpg.Portal/Menu/MainMenuViewComponent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@ private async Task<ProjectHeaderDto[]> GetProjectLinks()
5353
{
5454
return [];
5555
}
56-
return await projectRepository.GetMyProjects(currentUserAccessor.UserIdentification);
56+
return await projectRepository.GetProjectsBySpecification(currentUserAccessor.UserIdentification, ProjectListSpecification.MyActiveProjects);
5757
}
5858
}

src/JoinRpg.Web.ProjectCommon/Projects/CreateProjectPanel.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
<JoinAlert Variation="VariationStyleEnum.Info">Все настройки можно будет изменить после создания проекта.</JoinAlert>
4949
</FormRowFor>
5050
<FormRowFor For="@(() => Model.CopyFromProjectId)" hidden="@(Model.ProjectType != ProjectTypeViewModel.CopyFromAnother)">
51-
<ProjectSelector @bind-ProjectId="Model.CopyFromProjectId" />
51+
<ProjectSelector @bind-ProjectId="Model.CopyFromProjectId" Criteria="ProjectSelectionCriteria.ForCloning" />
5252
</FormRowFor>
5353
<FormRowFor For="@(() => Model.CopySettings)" hidden="@(Model.ProjectType != ProjectTypeViewModel.CopyFromAnother)">
5454
<EnumRadioButtonGroup @bind-SelectedValue="Model.CopySettings" />
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
namespace JoinRpg.Web.ProjectCommon.Projects;
22
public interface IProjectListClient
33
{
4-
Task<ProjectDto[]> GetProjectsWithMyMasterAccess();
4+
Task<ProjectDto[]> GetProjects(ProjectSelectionCriteria projectSelectionCriteria);
55
}

0 commit comments

Comments
 (0)