Skip to content

Commit e278593

Browse files
feat: Update file transport handling and improve compatibility across controllers and view models
1 parent 41e328f commit e278593

9 files changed

Lines changed: 111 additions & 17 deletions

File tree

src/XtremeIdiots.Portal.Web.Tests/Controllers/GameServersControllerTests.cs

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using XtremeIdiots.Portal.Web.Controllers;
2222
using XtremeIdiots.Portal.Web.Models;
2323
using XtremeIdiots.Portal.Web.ViewModels;
24+
using WebFileTransportType = XtremeIdiots.Portal.Web.Models.FileTransportType;
2425

2526
namespace XtremeIdiots.Portal.Web.Tests.Controllers;
2627

@@ -256,7 +257,7 @@ public async Task Edit_WhenUserCannotEditFileTransport_PreservesExistingFileTran
256257
QueryPort = existingServer.QueryPort,
257258
AgentEnabled = existingServer.AgentEnabled,
258259
FileTransportEnabled = true,
259-
FileTransportType = FileTransportType.Sftp,
260+
FileTransportType = WebFileTransportType.Sftp,
260261
RconEnabled = existingServer.RconEnabled,
261262
BanFileSyncEnabled = existingServer.BanFileSyncEnabled,
262263
BanFileRootPath = existingServer.BanFileRootPath,
@@ -274,13 +275,73 @@ public async Task Edit_WhenUserCannotEditFileTransport_PreservesExistingFileTran
274275
Assert.Equal("Index", redirect.ActionName);
275276
Assert.NotNull(capturedUpdate);
276277
Assert.True(capturedUpdate.FtpEnabled);
278+
Assert.True(capturedUpdate.FileTransportEnabled);
279+
Assert.Equal(XtremeIdiots.Portal.Repository.Abstractions.Constants.V1.FileTransportType.Ftp, capturedUpdate.FileTransportType);
280+
}
281+
282+
[Fact]
283+
public async Task Edit_WhenUserSelectsSftp_PersistsTransportEnabledAndType()
284+
{
285+
// Arrange
286+
var existingServer = CreateGameServerDto(ftpEnabled: true, fileTransportEnabled: true, fileTransportType: "Ftp");
287+
288+
mockRepositoryApiClient
289+
.Setup(x => x.GameServers.V1.GetGameServer(existingServer.GameServerId, It.IsAny<CancellationToken>()))
290+
.ReturnsAsync(new ApiResult<GameServerDto>(HttpStatusCode.OK, new ApiResponse<GameServerDto>(existingServer)));
291+
292+
EditGameServerDto? capturedUpdate = null;
293+
mockRepositoryApiClient
294+
.Setup(x => x.GameServers.V1.UpdateGameServer(It.IsAny<EditGameServerDto>(), It.IsAny<CancellationToken>()))
295+
.Callback<EditGameServerDto, CancellationToken>((dto, _) => capturedUpdate = dto)
296+
.ReturnsAsync(new ApiResult(HttpStatusCode.OK, new ApiResponse()));
297+
298+
mockAuthorizationService
299+
.Setup(x => x.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), AuthPolicies.GameServers_Write))
300+
.ReturnsAsync(AuthorizationResult.Success());
301+
302+
mockAuthorizationService
303+
.Setup(x => x.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), AuthPolicies.GameServers_Credentials_FileTransport_Write))
304+
.ReturnsAsync(AuthorizationResult.Success());
305+
306+
mockAuthorizationService
307+
.Setup(x => x.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), AuthPolicies.GameServers_Credentials_Rcon_Write))
308+
.ReturnsAsync(AuthorizationResult.Failed());
277309

278-
var optionalTransportType = capturedUpdate.GetType().GetProperty("FileTransportType", BindingFlags.Public | BindingFlags.Instance);
279-
if (optionalTransportType is not null)
310+
var model = new GameServerEditViewModel
280311
{
281-
var value = optionalTransportType.GetValue(capturedUpdate);
282-
Assert.Equal("Ftp", value?.ToString());
283-
}
312+
GameServer = new GameServerViewModel
313+
{
314+
GameServerId = existingServer.GameServerId,
315+
Title = existingServer.Title,
316+
GameType = existingServer.GameType,
317+
Hostname = existingServer.Hostname,
318+
QueryPort = existingServer.QueryPort,
319+
AgentEnabled = false,
320+
FileTransportEnabled = true,
321+
FileTransportType = WebFileTransportType.Sftp,
322+
RconEnabled = false,
323+
BanFileSyncEnabled = false,
324+
BanFileRootPath = "/",
325+
ServerListEnabled = false
326+
},
327+
FileTransportConfigHostname = "sftp.example.com",
328+
FileTransportConfigPort = 22,
329+
FileTransportConfigUsername = "test-user",
330+
FileTransportConfigPassword = "test-pass"
331+
};
332+
333+
var sut = CreateSut();
334+
335+
// Act
336+
var result = await sut.Edit(model, CancellationToken.None);
337+
338+
// Assert
339+
var redirect = Assert.IsType<RedirectToActionResult>(result);
340+
Assert.Equal("Index", redirect.ActionName);
341+
Assert.NotNull(capturedUpdate);
342+
Assert.True(capturedUpdate.FileTransportEnabled);
343+
Assert.Equal(XtremeIdiots.Portal.Repository.Abstractions.Constants.V1.FileTransportType.Sftp, capturedUpdate.FileTransportType);
344+
Assert.False(capturedUpdate.FtpEnabled);
284345
}
285346

286347
private static GameServerDto CreateGameServerDto(bool ftpEnabled, bool fileTransportEnabled, string fileTransportType)

src/XtremeIdiots.Portal.Web.Tests/Extensions/FileTransportCompatibilityExtensionsTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ private sealed class CompatibilitySource
1818
public ExternalFileTransportType? FileTransportType { get; set; }
1919
}
2020

21+
private sealed class CompatibilityTarget
22+
{
23+
public bool? FileTransportEnabled { get; set; }
24+
public ExternalFileTransportType? FileTransportType { get; set; }
25+
}
26+
2127
[Fact]
2228
public void GetFileTransportType_WhenTypeMissingAndLegacyFtpEnabled_InfersFtp()
2329
{
@@ -73,4 +79,29 @@ public void GetFileTransportType_WhenTypeProvided_UsesProvidedType()
7379

7480
Assert.Equal(FileTransportType.Sftp, result);
7581
}
82+
83+
[Fact]
84+
public void GetFileTransportType_WhenTypeIsUnknownAndLegacyFtpEnabled_InfersFtp()
85+
{
86+
var source = new CompatibilitySource
87+
{
88+
FileTransportEnabled = null,
89+
FileTransportType = ExternalFileTransportType.Unknown
90+
};
91+
92+
var result = source.GetFileTransportType(fileTransportEnabled: false, fallbackFtpEnabled: true);
93+
94+
Assert.Equal(FileTransportType.Ftp, result);
95+
}
96+
97+
[Fact]
98+
public void SetFileTransportProperties_WhenTargetSupportsOptionalFields_SetsBothFields()
99+
{
100+
var target = new CompatibilityTarget();
101+
102+
target.SetFileTransportProperties(fileTransportEnabled: true, fileTransportType: FileTransportType.Sftp);
103+
104+
Assert.True(target.FileTransportEnabled);
105+
Assert.Equal(ExternalFileTransportType.Sftp, target.FileTransportType);
106+
}
76107
}

src/XtremeIdiots.Portal.Web/Controllers/GameServersController.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using MX.Observability.ApplicationInsights.Auditing;
1414
using XtremeIdiots.Portal.Web.Models;
1515
using XtremeIdiots.Portal.Web.ViewModels;
16+
using WebFileTransportType = XtremeIdiots.Portal.Web.Models.FileTransportType;
1617

1718
namespace XtremeIdiots.Portal.Web.Controllers;
1819

@@ -151,7 +152,7 @@ public async Task<IActionResult> Create(GameServerViewModel model, CancellationT
151152

152153
createGameServerDto.AgentEnabled = model.AgentEnabled;
153154
createGameServerDto.SetFileTransportProperties(model.FileTransportEnabled, model.FileTransportType);
154-
createGameServerDto.FtpEnabled = model.FileTransportEnabled && model.FileTransportType == FileTransportType.Ftp;
155+
createGameServerDto.FtpEnabled = model.FileTransportEnabled && model.FileTransportType == WebFileTransportType.Ftp;
155156
createGameServerDto.RconEnabled = model.RconEnabled;
156157
createGameServerDto.BanFileSyncEnabled = model.BanFileSyncEnabled;
157158
createGameServerDto.BanFileRootPath = string.IsNullOrWhiteSpace(model.BanFileRootPath) ? "/" : model.BanFileRootPath;
@@ -242,12 +243,12 @@ public async Task<IActionResult> Details(Guid id, CancellationToken cancellation
242243
{
243244
case "ftp":
244245
case "sftp":
245-
var expectedNamespace = fileTransportType == FileTransportType.Sftp ? "sftp" : "ftp";
246+
var expectedNamespace = fileTransportType == WebFileTransportType.Sftp ? "sftp" : "ftp";
246247
if (!string.Equals(config.Namespace, expectedNamespace, StringComparison.OrdinalIgnoreCase))
247248
break;
248249

249250
ViewBag.FtpHostname = GetStringProperty(root, "hostname");
250-
ViewBag.FtpPort = GetIntProperty(root, "port", fileTransportType == FileTransportType.Sftp ? 22 : 21);
251+
ViewBag.FtpPort = GetIntProperty(root, "port", fileTransportType == WebFileTransportType.Sftp ? 22 : 21);
251252
ViewBag.FtpUsername = GetStringProperty(root, "username");
252253
ViewBag.FtpPassword = GetStringProperty(root, "password");
253254
ViewBag.FileTransportType = fileTransportType;
@@ -443,7 +444,7 @@ public async Task<IActionResult> Edit(GameServerEditViewModel model, Cancellatio
443444
: existingFileTransportType;
444445

445446
editGameServerDto.SetFileTransportProperties(selectedFileTransportEnabled, selectedFileTransportType);
446-
editGameServerDto.FtpEnabled = selectedFileTransportEnabled && selectedFileTransportType == FileTransportType.Ftp;
447+
editGameServerDto.FtpEnabled = selectedFileTransportEnabled && selectedFileTransportType == WebFileTransportType.Ftp;
447448
editGameServerDto.RconEnabled = model.GameServer.RconEnabled;
448449
editGameServerDto.BanFileSyncEnabled = model.GameServer.BanFileSyncEnabled;
449450
editGameServerDto.BanFileRootPath = string.IsNullOrWhiteSpace(model.GameServer.BanFileRootPath) ? "/" : model.GameServer.BanFileRootPath;

src/XtremeIdiots.Portal.Web/Controllers/MapRotationsController.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using MX.Observability.ApplicationInsights.Auditing;
1717
using XtremeIdiots.Portal.Web.Models;
1818
using XtremeIdiots.Portal.Web.ViewModels;
19+
using WebFileTransportType = XtremeIdiots.Portal.Web.Models.FileTransportType;
1920

2021
namespace XtremeIdiots.Portal.Web.Controllers;
2122

@@ -605,7 +606,7 @@ public async Task<IActionResult> EditAssignment(Guid id, CancellationToken cance
605606
var canBrowseFileTransport = await authorizationService.AuthorizeAsync(User, rotation.GameType, AuthPolicies.GameServers_Credentials_FileTransport_Write).ConfigureAwait(false);
606607

607608
var fileTransportEnabled = server?.GetFileTransportEnabled(server.FtpEnabled) ?? false;
608-
var fileTransportType = server?.GetFileTransportType(fileTransportEnabled, server.FtpEnabled) ?? FileTransportType.Unknown;
609+
var fileTransportType = server?.GetFileTransportType(fileTransportEnabled, server.FtpEnabled) ?? WebFileTransportType.Unknown;
609610

610611
ViewData["RotationTitle"] = rotation.Title;
611612

src/XtremeIdiots.Portal.Web/Extensions/FileTransportCompatibilityExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public static bool GetFileTransportEnabled(this object source, bool fallbackFtpE
1515
public static FileTransportType GetFileTransportType(this object source, bool fileTransportEnabled, bool fallbackFtpEnabled)
1616
{
1717
var value = source.GetOptionalEnumProperty("FileTransportType");
18-
if (value.HasValue)
18+
if (value.HasValue && value.Value != FileTransportType.Unknown)
1919
{
2020
return value.Value;
2121
}

src/XtremeIdiots.Portal.Web/ViewModels/EditMapRotationAssignmentViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.ComponentModel;
22
using System.ComponentModel.DataAnnotations;
3-
using XtremeIdiots.Portal.Repository.Abstractions.Constants.V1;
3+
using GameType = XtremeIdiots.Portal.Repository.Abstractions.Constants.V1.GameType;
44
using XtremeIdiots.Portal.Web.Models;
55

66
namespace XtremeIdiots.Portal.Web.ViewModels;

src/XtremeIdiots.Portal.Web/ViewModels/GameServerEditViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.ComponentModel;
22
using System.ComponentModel.DataAnnotations;
3-
using XtremeIdiots.Portal.Repository.Abstractions.Constants.V1;
3+
using GameType = XtremeIdiots.Portal.Repository.Abstractions.Constants.V1.GameType;
44
using XtremeIdiots.Portal.Web.Models;
55

66
namespace XtremeIdiots.Portal.Web.ViewModels;

src/XtremeIdiots.Portal.Web/ViewModels/GameServerViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.ComponentModel;
22
using System.ComponentModel.DataAnnotations;
3-
using XtremeIdiots.Portal.Repository.Abstractions.Constants.V1;
3+
using GameType = XtremeIdiots.Portal.Repository.Abstractions.Constants.V1.GameType;
44
using XtremeIdiots.Portal.Web.Models;
55

66
namespace XtremeIdiots.Portal.Web.ViewModels;

src/XtremeIdiots.Portal.Web/XtremeIdiots.Portal.Web.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
<PackageReference Include="MX.Api.Abstractions" Version="2.3.31" />
4949
<PackageReference Include="MX.Api.Client" Version="2.3.31" />
5050
<PackageReference Include="XtremeIdiots.Portal.Integrations.Servers.Api.Client.V1" Version="2.1.176" />
51-
<PackageReference Include="XtremeIdiots.Portal.Repository.Abstractions.V1" Version="2.1.236" />
52-
<PackageReference Include="XtremeIdiots.Portal.Repository.Api.Client.V1" Version="2.1.236" />
51+
<PackageReference Include="XtremeIdiots.Portal.Repository.Abstractions.V1" Version="2.1.240" />
52+
<PackageReference Include="XtremeIdiots.Portal.Repository.Api.Client.V1" Version="2.1.240" />
5353
<PackageReference Include="MX.GeoLocation.Api.Client.V1" Version="1.2.39" />
5454
</ItemGroup>
5555

0 commit comments

Comments
 (0)