diff --git a/NGitLab.Mock.Tests/ProjectsMockTests.cs b/NGitLab.Mock.Tests/ProjectsMockTests.cs index b3e9f27b..735af723 100644 --- a/NGitLab.Mock.Tests/ProjectsMockTests.cs +++ b/NGitLab.Mock.Tests/ProjectsMockTests.cs @@ -1,6 +1,8 @@ using System.Globalization; using System.IO; +using FluentAssertions; using NGitLab.Mock.Config; +using NGitLab.Models; using NUnit.Framework; namespace NGitLab.Mock.Tests @@ -76,10 +78,60 @@ public void Test_empty_repo() var user = server.Users.AddNew(); var project = user.Namespace.Projects.AddNew(); - Assert.IsTrue(project.ToClientProject().EmptyRepo); + Assert.IsTrue(project.ToClientProject(user).EmptyRepo); project.Repository.Commit(user, "dummy"); - Assert.IsFalse(project.ToClientProject().EmptyRepo); + Assert.IsFalse(project.ToClientProject(user).EmptyRepo); } + + [Test] + public void Test_project_permissions_maintainer_with_project_access() + { + using var server = new GitLabConfig() + .WithUser("Test", isDefault: true) + .WithProject("Test", @namespace: "testgroup", addDefaultUserAsMaintainer: true) + .BuildServer(); + + var client = server.CreateClient(); + var project = client.Projects["testgroup/Test"]; + + project.Should().NotBeNull(); + project.Permissions.GroupAccess.Should().BeNull(); + project.Permissions.ProjectAccess.AccessLevel.Should().Be(AccessLevel.Maintainer); + } + + [Test] + public void Test_project_permissions_with_no_access() + { + using var server = new GitLabConfig() + .WithUser("Test", isDefault: true) + .WithProject("Test", @namespace: "testgroup") + .BuildServer(); + + var client = server.CreateClient(); + var project = client.Projects["testgroup/Test"]; + + project.Should().NotBeNull(); + project.Permissions.GroupAccess.Should().BeNull(); + project.Permissions.ProjectAccess.Should().BeNull(); + } + + [Test] + public void Test_project_permissions_with_group_access() + { + using var server = new GitLabConfig() + .WithUser("Test", isDefault: true) + .WithGroup("testgroup", addDefaultUserAsMaintainer: true) + .WithProject("Test", @namespace: "testgroup") + .BuildServer(); + + var client = server.CreateClient(); + var project = client.Projects["testgroup/Test"]; + + project.Should().NotBeNull(); + project.Permissions.ProjectAccess.Should().BeNull(); + project.Permissions.GroupAccess.AccessLevel.Should().Be(AccessLevel.Maintainer); + } + } } diff --git a/NGitLab.Mock/Clients/GroupClient.cs b/NGitLab.Mock/Clients/GroupClient.cs index 58622ea9..78ebff51 100644 --- a/NGitLab.Mock/Clients/GroupClient.cs +++ b/NGitLab.Mock/Clients/GroupClient.cs @@ -26,7 +26,7 @@ public Models.Group this[int id] if (group == null || !group.CanUserViewGroup(Context.User)) throw new GitLabNotFoundException(); - return group.ToClientGroup(); + return group.ToClientGroup(Context.User); } } } @@ -41,7 +41,7 @@ public Models.Group this[string fullPath] if (group == null || !group.CanUserViewGroup(Context.User)) throw new GitLabNotFoundException(); - return group.ToClientGroup(); + return group.ToClientGroup(Context.User); } } } @@ -52,7 +52,7 @@ public IEnumerable Accessible { using (Context.BeginOperationScope()) { - return Server.AllGroups.Where(group => group.CanUserViewGroup(Context.User)).Select(group => group.ToClientGroup()).ToList(); + return Server.AllGroups.Where(group => group.CanUserViewGroup(Context.User)).Select(group => group.ToClientGroup(Context.User)).ToList(); } } } @@ -92,7 +92,7 @@ public Models.Group Create(GroupCreate group) Server.Groups.Add(newGroup); } - return newGroup.ToClientGroup(); + return newGroup.ToClientGroup(Context.User); } } @@ -114,7 +114,7 @@ public void Delete(int id) if (!group.CanUserDeleteGroup(Context.User)) throw new GitLabForbiddenException(); - group.ToClientGroup(); + group.ToClientGroup(Context.User); } } @@ -151,7 +151,7 @@ public async Task DeleteAsync(int id, CancellationToken cancellationToken = defa throw new NotImplementedException(); } - return groups.Select(g => g.ToClientGroup()).ToArray(); + return groups.Select(g => g.ToClientGroup(Context.User)).ToArray(); } } @@ -227,7 +227,7 @@ public void Restore(int id) } projects = projects.Where(project => project.CanUserViewProject(Context.User)); - return GitLabCollectionResponse.Create(projects.Select(project => project.ToClientProject()).ToArray()); + return GitLabCollectionResponse.Create(projects.Select(project => project.ToClientProject(Context.User)).ToArray()); } } @@ -282,7 +282,7 @@ public Models.Group Update(int id, GroupUpdate groupUpdate) group.Visibility = groupUpdate.Visibility.Value; } - return group.ToClientGroup(); + return group.ToClientGroup(Context.User); } } @@ -320,7 +320,7 @@ public Models.Group Update(int id, GroupUpdate groupUpdate) throw new NotImplementedException(); } - var clientGroups = groups.Select(g => g.ToClientGroup()); + var clientGroups = groups.Select(g => g.ToClientGroup(Context.User)); return GitLabCollectionResponse.Create(clientGroups.Where(g => g.ParentId == parentGroup.Id)); } @@ -353,7 +353,7 @@ public Models.Group Update(int id, GroupUpdate groupUpdate) throw new NotImplementedException(); } - var clientGroups = groups.Select(g => g.ToClientGroup()); + var clientGroups = groups.Select(g => g.ToClientGroup(Context.User)); return GitLabCollectionResponse.Create(clientGroups.Where(g => g.ParentId == parentGroup.Id)); } diff --git a/NGitLab.Mock/Clients/ProjectClient.cs b/NGitLab.Mock/Clients/ProjectClient.cs index df774ba3..5cbcfd5c 100644 --- a/NGitLab.Mock/Clients/ProjectClient.cs +++ b/NGitLab.Mock/Clients/ProjectClient.cs @@ -27,7 +27,7 @@ public Models.Project this[int id] if (project == null || !project.CanUserViewProject(Context.User)) throw new GitLabNotFoundException(); - return project.ToClientProject(); + return project.ToClientProject(Context.User); } } } @@ -39,7 +39,7 @@ public Models.Project this[string fullName] using (Context.BeginOperationScope()) { var project = GetProject(fullName, ProjectPermission.View); - return project.ToClientProject(); + return project.ToClientProject(Context.User); } } } @@ -50,7 +50,7 @@ public IEnumerable Accessible { using (Context.BeginOperationScope()) { - return Server.AllProjects.Where(project => project.IsUserMember(Context.User)).Select(project => project.ToClientProject()).ToList(); + return Server.AllProjects.Where(project => project.IsUserMember(Context.User)).Select(project => project.ToClientProject(Context.User)).ToList(); } } } @@ -61,7 +61,7 @@ public IEnumerable Owned { using (Context.BeginOperationScope()) { - return Server.AllProjects.Where(project => project.IsUserOwner(Context.User)).Select(project => project.ToClientProject()).ToList(); + return Server.AllProjects.Where(project => project.IsUserOwner(Context.User)).Select(project => project.ToClientProject(Context.User)).ToList(); } } } @@ -72,7 +72,7 @@ public IEnumerable Visible { using (Context.BeginOperationScope()) { - return Server.AllProjects.Where(project => project.CanUserViewProject(Context.User)).Select(project => project.ToClientProject()).ToList(); + return Server.AllProjects.Where(project => project.CanUserViewProject(Context.User)).Select(project => project.ToClientProject(Context.User)).ToList(); } } } @@ -94,7 +94,7 @@ public Models.Project Create(ProjectCreate project) }; parentGroup.Projects.Add(newProject); - return newProject.ToClientProject(); + return newProject.ToClientProject(Context.User); } } @@ -151,7 +151,7 @@ public Models.Project Fork(string id, ForkProject forkProject) var project = GetProject(id, ProjectPermission.View); var group = forkProject.Namespace != null ? GetParentGroup(forkProject.Namespace) : Context.User.Namespace; var newProject = project.Fork(group, Context.User, forkProject.Name); - return newProject.ToClientProject(); + return newProject.ToClientProject(Context.User); } } @@ -220,7 +220,7 @@ public Models.Project Fork(string id, ForkProject forkProject) throw new NotImplementedException(); } - return projects.Select(project => project.ToClientProject()).ToList(); + return projects.Select(project => project.ToClientProject(Context.User)).ToList(); } } @@ -228,7 +228,7 @@ public Models.Project GetById(int id, SingleProjectQuery query) { using (Context.BeginOperationScope()) { - return GetProject(id, ProjectPermission.View).ToClientProject(); + return GetProject(id, ProjectPermission.View).ToClientProject(Context.User); } } @@ -265,7 +265,7 @@ public Models.Project GetById(int id, SingleProjectQuery query) var matches = Server.AllProjects.Where(project => project.ForkedFrom?.Id == upstream.Id); matches = matches.Where(project => query.Owned == null || query.Owned == project.IsUserOwner(Context.User)); - return matches.Select(project => project.ToClientProject()).ToList(); + return matches.Select(project => project.ToClientProject(Context.User)).ToList(); } } @@ -352,7 +352,7 @@ public Models.Project Update(string id, ProjectUpdate projectUpdate) project.Topics = projectUpdate.Topics.Where(t => !string.IsNullOrEmpty(t)).Distinct(StringComparer.Ordinal).ToArray(); } - return project.ToClientProject(); + return project.ToClientProject(Context.User); } } diff --git a/NGitLab.Mock/Clients/RunnerClient.cs b/NGitLab.Mock/Clients/RunnerClient.cs index c9bed105..492d9619 100644 --- a/NGitLab.Mock/Clients/RunnerClient.cs +++ b/NGitLab.Mock/Clients/RunnerClient.cs @@ -11,7 +11,16 @@ namespace NGitLab.Mock.Clients { internal sealed class RunnerClient : ClientBase, IRunnerClient { - public IEnumerable Accessible => GetOwnedRunners().Select(r => r.ToClientRunner()); + public IEnumerable Accessible + { + get + { + using (Context.BeginOperationScope()) + { + return GetOwnedRunners().Select(r => r.ToClientRunner(Context.User)); + } + } + } public IEnumerable All { @@ -25,7 +34,7 @@ public IEnumerable All using (Context.BeginOperationScope()) { var runners = Server.AllProjects.SelectMany(p => p.RegisteredRunners); - var clientRunners = runners.Select(r => r.ToClientRunner()).ToList(); + var clientRunners = runners.Select(r => r.ToClientRunner(Context.User)).ToList(); return clientRunners; } } @@ -125,7 +134,7 @@ public Models.Runner EnableRunner(int projectId, RunnerId runnerId) } project.EnabledRunners.Add(runnerReference); - return runner.ToClientRunner(); + return runner.ToClientRunner(Context.User); } } diff --git a/NGitLab.Mock/Group.cs b/NGitLab.Mock/Group.cs index 7c988062..fb9908b8 100644 --- a/NGitLab.Mock/Group.cs +++ b/NGitLab.Mock/Group.cs @@ -235,7 +235,7 @@ public bool CanUserAddProject(User user) return accessLevel.HasValue && accessLevel.Value >= AccessLevel.Developer; } - public Models.Group ToClientGroup() + public Models.Group ToClientGroup(User currentUser) { return new Models.Group { @@ -243,7 +243,7 @@ public Models.Group ToClientGroup() Name = Name, Visibility = Visibility, ParentId = Parent?.Id, - Projects = Projects.Select(p => p.ToClientProject()).ToArray(), + Projects = Projects.Select(p => p.ToClientProject(currentUser)).ToArray(), FullName = FullName, FullPath = PathWithNameSpace, Path = Path, diff --git a/NGitLab.Mock/Project.cs b/NGitLab.Mock/Project.cs index 22bbefe3..197e07e8 100644 --- a/NGitLab.Mock/Project.cs +++ b/NGitLab.Mock/Project.cs @@ -399,7 +399,7 @@ public Project Fork(Group group, User user, string projectName) return newProject; } - public Models.Project ToClientProject() + public Models.Project ToClientProject(User currentUser) { var kind = Group.IsUserNamespace ? "user" : "group"; @@ -412,7 +412,7 @@ public Models.Project ToClientProject() EmptyRepo = Repository.IsEmpty, Path = Path, PathWithNamespace = PathWithNamespace, - ForkedFromProject = ForkedFrom?.ToClientProject(), + ForkedFromProject = ForkedFrom?.ToClientProject(currentUser), ForkingAccessLevel = ForkingAccessLevel, ImportStatus = ImportStatus, HttpUrl = HttpUrl, @@ -435,8 +435,25 @@ public Models.Project ToClientProject() MirrorTriggerBuilds = MirrorTriggerBuilds, OnlyMirrorProtectedBranch = OnlyMirrorProtectedBranch, MirrorOverwritesDivergedBranches = MirrorOverwritesDivergedBranches, + Permissions = GetProjectPermissions(currentUser), }; #pragma warning restore CS0618 // Type or member is obsolete } + + private ProjectPermissions GetProjectPermissions(User user) + { + var projectPermissions = new ProjectPermissions(); + if (Permissions.FirstOrDefault(x => x.User == user)?.AccessLevel is { } accessLevel) + { + projectPermissions.ProjectAccess = new ProjectPermission { AccessLevel = accessLevel }; + } + + if (Group.GetEffectivePermissions().GetAccessLevel(user) is { } groupAccessLevel) + { + projectPermissions.GroupAccess = new ProjectPermission { AccessLevel = groupAccessLevel }; + } + + return projectPermissions; + } } } diff --git a/NGitLab.Mock/PublicAPI.Unshipped.txt b/NGitLab.Mock/PublicAPI.Unshipped.txt index 9ca8ba33..0410bf1e 100644 --- a/NGitLab.Mock/PublicAPI.Unshipped.txt +++ b/NGitLab.Mock/PublicAPI.Unshipped.txt @@ -455,7 +455,7 @@ NGitLab.Mock.Group.RequestAccessEnabled.get -> bool NGitLab.Mock.Group.RequestAccessEnabled.set -> void NGitLab.Mock.Group.SharedRunnersLimit.get -> System.TimeSpan NGitLab.Mock.Group.SharedRunnersLimit.set -> void -NGitLab.Mock.Group.ToClientGroup() -> NGitLab.Models.Group +NGitLab.Mock.Group.ToClientGroup(NGitLab.Mock.User currentUser) -> NGitLab.Models.Group NGitLab.Mock.Group.Visibility.get -> NGitLab.Models.VisibilityLevel NGitLab.Mock.Group.Visibility.set -> void NGitLab.Mock.GroupCollection @@ -849,7 +849,7 @@ NGitLab.Mock.Project.Statistics.get -> NGitLab.Models.ProjectStatistics NGitLab.Mock.Project.Statistics.set -> void NGitLab.Mock.Project.Tags.get -> string[] NGitLab.Mock.Project.Tags.set -> void -NGitLab.Mock.Project.ToClientProject() -> NGitLab.Models.Project +NGitLab.Mock.Project.ToClientProject(NGitLab.Mock.User currentUser) -> NGitLab.Models.Project NGitLab.Mock.Project.Topics.get -> string[] NGitLab.Mock.Project.Topics.set -> void NGitLab.Mock.Project.Visibility.get -> NGitLab.Models.VisibilityLevel diff --git a/NGitLab.Mock/Runner.cs b/NGitLab.Mock/Runner.cs index 96550a36..743b5809 100644 --- a/NGitLab.Mock/Runner.cs +++ b/NGitLab.Mock/Runner.cs @@ -35,7 +35,7 @@ public sealed class Runner : GitLabObject public bool RunUntagged { get; set; } - internal Models.Runner ToClientRunner() + internal Models.Runner ToClientRunner(User currentUser) { return new Models.Runner { @@ -46,7 +46,7 @@ internal Models.Runner ToClientRunner() Status = Status, Description = Description, IsShared = IsShared, - Projects = Parent.Server.AllProjects.Where(p => p.EnabledRunners.Any(r => r.Id == Id)).Select(p => p.ToClientProject()).ToArray(), + Projects = Parent.Server.AllProjects.Where(p => p.EnabledRunners.Any(r => r.Id == Id)).Select(p => p.ToClientProject(currentUser)).ToArray(), ContactedAt = ContactedAt, Token = Token, TagList = TagList,