Skip to content

Commit f5e6729

Browse files
authored
Merge pull request #2765 from wabbajack-tools/4.0.1.0-validation
Several changes for 4.0.1.0
2 parents 93ba1d0 + 93570b2 commit f5e6729

File tree

17 files changed

+170
-92
lines changed

17 files changed

+170
-92
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* Added 2FA support for MEGA login, added some extra logging for MEGA logins
77
* Special thanks to [@erri120](https://www.github.com/erri120) who originally implemented part of this in Wabbajack and the MegaApiClient library 4 years ago, which made the change rather easy
88
* Added a warning for when WebView is not loading
9-
* Addd progress indicator to the publish button after compilation (thanks to [@JanuarySnow](https://www.github.com/JanuarySnow)))
9+
* Add progress indicator to the publish button after compilation (thanks to [@JanuarySnow](https://www.github.com/JanuarySnow)))
10+
* Improve validation before being able to install, should avoid users installing to important folders/the Wabbajack installation directory
1011

1112
#### Version - 4.0.0.3 - 3/20/2025
1213
* Fixed the open logs folder button not actually opening the logs folder on a failed installation
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Wabbajack
2+
{
3+
public class DownloadsPathValidationResult : ValidationResult
4+
{
5+
public override string ToString()
6+
{
7+
return $"({(Succeeded ? "Success" : "Fail")}, {Reason})";
8+
}
9+
}
10+
}

Wabbajack.App.Wpf/Error States/GetResponse.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Wabbajack
44
{
5-
public struct GetResponse<T> : IEquatable<GetResponse<T>>, IErrorResponse
5+
public struct GetResponse<T> : IEquatable<GetResponse<T>>, IValidationResult
66
{
77
public static readonly GetResponse<T> Failure = new GetResponse<T>();
88

@@ -24,8 +24,8 @@ public string Reason
2424
}
2525
}
2626

27-
bool IErrorResponse.Succeeded => Succeeded;
28-
Exception? IErrorResponse.Exception => Exception;
27+
bool IValidationResult.Succeeded => Succeeded;
28+
Exception? IValidationResult.Exception => Exception;
2929

3030
private GetResponse(
3131
bool succeeded,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Wabbajack
2+
{
3+
public class InstallPathValidationResult : ValidationResult
4+
{
5+
public override string ToString()
6+
{
7+
return $"({(Succeeded ? "Success" : "Fail")}, {Reason})";
8+
}
9+
}
10+
}

Wabbajack.App.Wpf/Error States/ErrorResponse.cs renamed to Wabbajack.App.Wpf/Error States/ValidationResult.cs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
namespace Wabbajack
66
{
7-
public struct ErrorResponse : IErrorResponse
7+
public class ValidationResult : IValidationResult
88
{
9-
public static readonly ErrorResponse Success = Succeed();
10-
public static readonly ErrorResponse Failure = new();
9+
public static readonly ValidationResult Success = Succeed();
10+
public static readonly ValidationResult Failure = new();
1111

1212
public bool Succeeded { get; }
1313
public Exception? Exception { get; }
14-
private readonly string _reason;
14+
protected readonly string _reason;
1515

1616
public bool Failed => !Succeeded;
1717
public string Reason
@@ -33,10 +33,11 @@ public string Reason
3333
}
3434
}
3535

36-
bool IErrorResponse.Succeeded => Succeeded;
37-
Exception? IErrorResponse.Exception => Exception;
36+
bool IValidationResult.Succeeded => Succeeded;
37+
Exception? IValidationResult.Exception => Exception;
3838

39-
private ErrorResponse(
39+
protected ValidationResult() { }
40+
protected ValidationResult(
4041
bool succeeded,
4142
string? reason = null,
4243
Exception? ex = null)
@@ -52,61 +53,61 @@ public override string ToString()
5253
}
5354

5455
#region Factories
55-
public static ErrorResponse Succeed()
56+
public static ValidationResult Succeed()
5657
{
57-
return new ErrorResponse(true);
58+
return new ValidationResult(true);
5859
}
5960

60-
public static ErrorResponse Succeed(string reason)
61+
public static ValidationResult Succeed(string reason)
6162
{
62-
return new ErrorResponse(true, reason);
63+
return new ValidationResult(true, reason);
6364
}
6465

65-
public static ErrorResponse Fail(string reason, Exception? ex = null)
66+
public static ValidationResult Fail(string reason, Exception? ex = null)
6667
{
67-
return new ErrorResponse(false, reason: reason, ex: ex);
68+
return new ValidationResult(false, reason: reason, ex: ex);
6869
}
6970

70-
public static ErrorResponse Fail(Exception ex)
71+
public static ValidationResult Fail(Exception ex)
7172
{
72-
return new ErrorResponse(false, ex: ex);
73+
return new ValidationResult(false, ex: ex);
7374
}
7475

75-
public static ErrorResponse Fail()
76+
public static ValidationResult Fail()
7677
{
77-
return new ErrorResponse(false);
78+
return new ValidationResult(false);
7879
}
7980

80-
public static ErrorResponse Create(bool successful, string? reason = null)
81+
public static ValidationResult Create(bool successful, string? reason = null)
8182
{
82-
return new ErrorResponse(successful, reason);
83+
return new ValidationResult(successful, reason);
8384
}
8485
#endregion
8586

86-
public static ErrorResponse Convert(IErrorResponse err, bool nullIsSuccess = true)
87+
public static ValidationResult Convert(IValidationResult err, bool nullIsSuccess = true)
8788
{
8889
if (err == null) return Create(nullIsSuccess);
89-
return new ErrorResponse(err.Succeeded, err.Reason, err.Exception);
90+
return new ValidationResult(err.Succeeded, err.Reason, err.Exception);
9091
}
9192

92-
public static ErrorResponse FirstFail(params ErrorResponse[] responses)
93+
public static ValidationResult FirstFail(params ValidationResult[] responses)
9394
{
9495
foreach (var resp in responses)
9596
{
9697
if (resp.Failed) return resp;
9798
}
98-
return ErrorResponse.Success;
99+
return ValidationResult.Success;
99100
}
100101

101-
public static ErrorResponse Combine(List<ErrorResponse> errors)
102+
public static ValidationResult Combine(List<ValidationResult> errors)
102103
{
103104
if (errors.All(e => e.Succeeded) || !errors.Any())
104105
return Success;
105106
return Fail(string.Join("\n", errors.Where(e => e.Failed).Select(e => e.Reason)));
106107
}
107108
}
108109

109-
public interface IErrorResponse
110+
public interface IValidationResult
110111
{
111112
bool Succeeded { get; }
112113
Exception? Exception { get; }

Wabbajack.App.Wpf/LoadingLock.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class LoadingLock : ReactiveObject, IDisposable
1111
private readonly CompositeDisposable _disposable;
1212

1313
[Reactive]
14-
public ErrorResponse? ErrorState { get; set; }
14+
public ValidationResult? ErrorState { get; set; }
1515

1616
public LoadingLock()
1717
{
@@ -64,13 +64,13 @@ public LockContext(LoadingLock parent)
6464

6565
public void Succeed()
6666
{
67-
_parent.ErrorState = ErrorResponse.Success;
67+
_parent.ErrorState = ValidationResult.Success;
6868
Dispose();
6969
}
7070

7171
public void Fail()
7272
{
73-
_parent.ErrorState = ErrorResponse.Failure;
73+
_parent.ErrorState = ValidationResult.Failure;
7474
Dispose();
7575
}
7676

Wabbajack.App.Wpf/Util/FilePickerVM.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ public enum CheckOptions
5353
public CheckOptions FilterCheckOption { get; set; } = CheckOptions.IfPathNotEmpty;
5454

5555
[Reactive]
56-
public IObservable<IErrorResponse> AdditionalError { get; set; }
56+
public IObservable<IValidationResult> AdditionalError { get; set; }
5757

5858
private readonly ObservableAsPropertyHelper<bool> _exists;
5959
public bool Exists => _exists.Value;
6060

61-
private readonly ObservableAsPropertyHelper<ErrorResponse> _errorState;
62-
public ErrorResponse ErrorState => _errorState.Value;
61+
private readonly ObservableAsPropertyHelper<ValidationResult> _validationResult;
62+
public ValidationResult ValidationResult => _validationResult.Value;
6363

6464
private readonly ObservableAsPropertyHelper<bool> _inError;
6565
public bool InError => _inError.Value;
@@ -196,32 +196,32 @@ public FilePickerVM(object parentVM = null)
196196
.StartWith(true)
197197
.Select(passed =>
198198
{
199-
if (passed) return ErrorResponse.Success;
200-
return ErrorResponse.Fail(DoesNotPassFiltersText);
199+
if (passed) return ValidationResult.Success;
200+
return ValidationResult.Fail(DoesNotPassFiltersText);
201201
})
202202
.Replay(1)
203203
.RefCount();
204204

205-
_errorState = Observable.CombineLatest(
205+
_validationResult = Observable.CombineLatest(
206206
Observable.CombineLatest(
207207
this.WhenAny(x => x.Exists),
208208
doExistsCheck,
209209
resultSelector: (exists, doExists) => !doExists || exists)
210-
.Select(exists => ErrorResponse.Create(successful: exists, exists ? default(string) : PathDoesNotExistText)),
210+
.Select(exists => ValidationResult.Create(successful: exists, exists ? default(string) : PathDoesNotExistText)),
211211
passesFilters,
212212
this.WhenAny(x => x.AdditionalError)
213-
.Select(x => x ?? Observable.Return<IErrorResponse>(ErrorResponse.Success))
213+
.Select(x => x ?? Observable.Return<IValidationResult>(ValidationResult.Success))
214214
.Switch(),
215215
resultSelector: (existCheck, filter, err) =>
216216
{
217217
if (existCheck.Failed) return existCheck;
218218
if (filter.Failed) return filter;
219-
return ErrorResponse.Convert(err);
219+
return ValidationResult.Convert(err);
220220
})
221-
.ToGuiProperty(this, nameof(ErrorState));
221+
.ToGuiProperty(this, nameof(ValidationResult));
222222

223-
_inError = this.WhenAny(x => x.ErrorState)
224-
.Select(x => !x.Succeeded)
223+
_inError = this.WhenAny(x => x.ValidationResult)
224+
.Select(x => x != null && !x.Succeeded)
225225
.ToGuiProperty(this, nameof(InError));
226226

227227
// Doesn't derive from ErrorState, as we want to bubble non-empty tooltips,
@@ -235,7 +235,7 @@ public FilePickerVM(object parentVM = null)
235235
passesFilters
236236
.Select(x => x.Reason),
237237
this.WhenAny(x => x.AdditionalError)
238-
.Select(x => x ?? Observable.Return<IErrorResponse>(ErrorResponse.Success))
238+
.Select(x => x ?? Observable.Return<IValidationResult>(ValidationResult.Success))
239239
.Switch(),
240240
resultSelector: (exists, filters, err) =>
241241
{

Wabbajack.App.Wpf/ViewModels/Compiler/CompilerDetailsVM.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class CompilerDetailsVM : BaseCompilerVM, ICpuStatusVM
6565
public ReadOnlyObservableCollection<CPUDisplayVM> StatusList => _resourceMonitor.Tasks;
6666

6767
[Reactive]
68-
public ErrorResponse ErrorState { get; private set; }
68+
public ValidationResult ErrorState { get; private set; }
6969

7070
public CompilerDetailsVM(ILogger<CompilerDetailsVM> logger, DTOSerializer dtos, SettingsManager settingsManager,
7171
IServiceProvider serviceProvider, LogStream loggerProvider, ResourceMonitor resourceMonitor,
@@ -139,9 +139,9 @@ public CompilerDetailsVM(ILogger<CompilerDetailsVM> logger, DTOSerializer dtos,
139139
this.WhenAnyValue(x => x.DownloadLocation.TargetPath)
140140
.CombineLatest(this.WhenAnyValue(x => x.ModlistLocation.TargetPath),
141141
this.WhenAnyValue(x => x.OutputLocation.TargetPath),
142-
this.WhenAnyValue(x => x.DownloadLocation.ErrorState),
143-
this.WhenAnyValue(x => x.ModlistLocation.ErrorState),
144-
this.WhenAnyValue(x => x.OutputLocation.ErrorState))
142+
this.WhenAnyValue(x => x.DownloadLocation.ValidationResult),
143+
this.WhenAnyValue(x => x.ModlistLocation.ValidationResult),
144+
this.WhenAnyValue(x => x.OutputLocation.ValidationResult))
145145
.Select(_ => Validate())
146146
.BindToStrict(this, vm => vm.ErrorState)
147147
.DisposeWith(disposables);
@@ -181,15 +181,15 @@ private async Task ReInferSettings(AbsolutePath filePath)
181181
Settings.AdditionalProfiles = newSettings.AdditionalProfiles;
182182
}
183183

184-
private ErrorResponse Validate()
184+
private ValidationResult Validate()
185185
{
186-
var errors = new List<ErrorResponse>
186+
var errors = new List<ValidationResult>
187187
{
188-
DownloadLocation.ErrorState,
189-
ModlistLocation.ErrorState,
190-
OutputLocation.ErrorState
188+
DownloadLocation.ValidationResult,
189+
ModlistLocation.ValidationResult,
190+
OutputLocation.ValidationResult
191191
};
192-
return ErrorResponse.Combine(errors);
192+
return ValidationResult.Combine(errors);
193193
}
194194

195195
private async Task<CompilerSettings> InferModListFromLocation(AbsolutePath path)

Wabbajack.App.Wpf/ViewModels/Gallery/BaseModListMetadataVM.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class BaseModListMetadataVM : ViewModel
6060
[Reactive] public ICommand DetailsCommand { get; set; }
6161
[Reactive] public ICommand InstallCommand { get; protected set; }
6262

63-
[Reactive] public IErrorResponse Error { get; protected set; }
63+
[Reactive] public IValidationResult Error { get; protected set; }
6464

6565
protected ObservableAsPropertyHelper<BitmapImage> _Image { get; set; }
6666
public BitmapImage Image => _Image.Value;

Wabbajack.App.Wpf/ViewModels/Gallery/ModListGalleryVM.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public GameTypeEntry(GameMetaData gameMetaData, int amount)
6060

6161
private const string ALL_GAME_IDENTIFIER = "All games";
6262

63-
[Reactive] public IErrorResponse Error { get; set; }
63+
[Reactive] public IValidationResult Error { get; set; }
6464

6565
[Reactive] public string Search { get; set; }
6666

0 commit comments

Comments
 (0)