diff --git a/src/BreCalClient/BreCalClient.csproj b/src/BreCalClient/BreCalClient.csproj
index 66d3357..ed82cb5 100644
--- a/src/BreCalClient/BreCalClient.csproj
+++ b/src/BreCalClient/BreCalClient.csproj
@@ -8,8 +8,8 @@
True
BreCalClient.App
..\..\misc\brecal.snk
- 1.5.0.8
- 1.5.0.8
+ 1.5.0.12
+ 1.5.0.12
Bremen calling client
A Windows WPF client for the Bremen calling API.
containership.ico
diff --git a/src/BreCalClient/EditShipcallControl.xaml.cs b/src/BreCalClient/EditShipcallControl.xaml.cs
index fd42086..8609f0a 100644
--- a/src/BreCalClient/EditShipcallControl.xaml.cs
+++ b/src/BreCalClient/EditShipcallControl.xaml.cs
@@ -204,26 +204,22 @@ namespace BreCalClient
{
case ShipcallType.Departure:
isEnabled &= this.comboBoxDepartureBerth.SelectedItem != null;
- isEnabled &= this.datePickerETD.Value.HasValue;
- if(this.datePickerETD.Value.HasValue)
- isEnabled &= (this.datePickerETD.Value.Value > DateTime.Now);
+ isEnabled &= this.datePickerETD.Value.HasValue;
+ isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
isEnabled &= !this.datePickerETD.Value.IsTooFar();
break;
case ShipcallType.Arrival:
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
- isEnabled &= this.datePickerETA.Value.HasValue;
- if(this.datePickerETA.Value.HasValue)
- isEnabled &= (this.datePickerETA.Value.Value > DateTime.Now);
+ isEnabled &= this.datePickerETA.Value.HasValue;
+ isEnabled &= !(this.datePickerETA.Value.IsTooOld() && this.datePickerETA.Value != this.ShipcallModel.Shipcall?.Eta);
isEnabled &= !this.datePickerETA.Value.IsTooFar();
break;
case ShipcallType.Shifting:
isEnabled &= ((this.comboBoxDepartureBerth.SelectedItem != null) && (this.comboBoxArrivalBerth.SelectedItem != null));
isEnabled &= this.datePickerETD.Value.HasValue;
- isEnabled &= this.datePickerETA.Value.HasValue;
- if (this.datePickerETD.Value.HasValue)
- isEnabled &= (this.datePickerETD.Value.Value > DateTime.Now);
- if (this.datePickerETA.Value.HasValue)
- isEnabled &= (this.datePickerETA.Value.Value > DateTime.Now);
+ isEnabled &= this.datePickerETA.Value.HasValue;
+ isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
+ isEnabled &= !(this.datePickerETA.Value.IsTooOld() && this.datePickerETA.Value != this.ShipcallModel.Shipcall?.Eta);
if (this.datePickerETA.Value.HasValue && this.datePickerETD.Value.HasValue)
isEnabled &= (this.datePickerETA.Value.Value > this.datePickerETD.Value.Value);
isEnabled &= !this.datePickerETD.Value.IsTooFar();
diff --git a/src/BreCalClient/EditTimesAgencyIncomingControl.xaml.cs b/src/BreCalClient/EditTimesAgencyIncomingControl.xaml.cs
index 8d85d68..e3ef1c1 100644
--- a/src/BreCalClient/EditTimesAgencyIncomingControl.xaml.cs
+++ b/src/BreCalClient/EditTimesAgencyIncomingControl.xaml.cs
@@ -4,7 +4,6 @@
using BreCalClient.misc.Model;
using System;
-using System.Runtime.Serialization;
using System.Windows;
using static BreCalClient.Extensions;
@@ -97,47 +96,41 @@ namespace BreCalClient
{
message = "";
- if (this.datePickerETA.Value.HasValue && (this.datePickerETA.Value.Value < DateTime.Now) && (this.datePickerETA_End.Value == null))
- {
- message = BreCalClient.Resources.Resources.textETAInThePast;
- return false;
- }
-
- if(this.datePickerETA_End.Value.HasValue && this.datePickerETA_End.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textETAInThePast;
- return false;
- }
-
- if(this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
+ if ((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd)) // something has changed
{
- message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
- return false;
+ if (datePickerETA.Value.IsTooOld() || datePickerETA_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textETAInThePast;
+ return false;
+ }
+
+ if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
+ {
+ message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
+ return false;
+ }
}
- if (this.datePickerTidalWindowFrom.Value.HasValue && (this.datePickerTidalWindowFrom.Value.Value < DateTime.Now) && (this.datePickerTidalWindowTo.Value == null))
+ if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo)) // something has changed
{
- message = BreCalClient.Resources.Resources.textTideTimesInThePast;
- return false;
- }
+ if(datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textTideTimesInThePast;
+ return false;
+ }
- if (this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowTo.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textTideTimesInThePast;
- return false;
- }
+ if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
+ {
+ message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
+ return false;
+ }
- if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
- {
- message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
- return false;
- }
-
- if((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
- {
- message = BreCalClient.Resources.Resources.textTidalBothValues;
- return false;
- }
+ if ((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
+ {
+ message = BreCalClient.Resources.Resources.textTidalBothValues;
+ return false;
+ }
+ }
if(this.datePickerETA.Value.IsTooFar() || this.datePickerETA_End.Value.IsTooFar() || this.datePickerTidalWindowFrom.Value.IsTooFar() || this.datePickerTidalWindowTo.Value.IsTooFar())
{
@@ -145,8 +138,7 @@ namespace BreCalClient
return false;
}
- if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) ||
- (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
+ if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
{
message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false;
diff --git a/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml.cs b/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml.cs
index c850ed8..04af41e 100644
--- a/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml.cs
+++ b/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml.cs
@@ -4,15 +4,8 @@
using BreCalClient.misc.Model;
using System;
-using System.Text.RegularExpressions;
using System.Windows;
-using System.Windows.Controls.Primitives;
-using System.Windows.Controls;
-using Xceed.Wpf.Toolkit;
using static BreCalClient.Extensions;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows.Media;
namespace BreCalClient
{
@@ -107,17 +100,14 @@ namespace BreCalClient
{
message = "";
- if (this.datePickerETD.Value.HasValue && (this.datePickerETD.Value.Value < DateTime.Now) && (this.datePickerETD_End.Value == null))
+ if((this.datePickerETD.Value != this.Times.EtdBerth) || (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
{
- message = BreCalClient.Resources.Resources.textETDInThePast;
- return false;
- }
-
- if (this.datePickerETD_End.Value.HasValue && this.datePickerETD_End.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textETDInThePast;
- return false;
- }
+ if (datePickerETD.Value.IsTooOld() || datePickerETD_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textETDInThePast;
+ return false;
+ }
+ }
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
{
@@ -125,17 +115,14 @@ namespace BreCalClient
return false;
}
- if (this.datePickerTidalWindowFrom.Value.HasValue && (this.datePickerTidalWindowFrom.Value.Value < DateTime.Now) && (this.datePickerTidalWindowTo.Value == null))
+ if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
{
- message = BreCalClient.Resources.Resources.textTideTimesInThePast;
- return false;
- }
-
- if (this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowTo.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textTideTimesInThePast;
- return false;
- }
+ if (this.datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textTideTimesInThePast;
+ return false;
+ }
+ }
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
{
@@ -155,8 +142,7 @@ namespace BreCalClient
return false;
}
- if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) ||
- (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
+ if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
{
message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false;
diff --git a/src/BreCalClient/EditTimesAgencyShiftingControl.xaml.cs b/src/BreCalClient/EditTimesAgencyShiftingControl.xaml.cs
index 9307943..5495560 100644
--- a/src/BreCalClient/EditTimesAgencyShiftingControl.xaml.cs
+++ b/src/BreCalClient/EditTimesAgencyShiftingControl.xaml.cs
@@ -97,17 +97,15 @@ namespace BreCalClient
{
message = "";
- if (this.datePickerETA.Value.HasValue && (this.datePickerETA.Value.Value < DateTime.Now) && (this.datePickerETA_End.Value == null))
- {
- message = BreCalClient.Resources.Resources.textETAInThePast;
- return false;
- }
- if (this.datePickerETA_End.Value.HasValue && this.datePickerETA_End.Value < DateTime.Now)
+ if((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd))
{
- message = BreCalClient.Resources.Resources.textETAInThePast;
- return false;
- }
+ if (this.datePickerETA.Value.IsTooOld() && this.datePickerETA_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textETAInThePast;
+ return false;
+ }
+ }
if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
{
@@ -115,17 +113,14 @@ namespace BreCalClient
return false;
}
- if (this.datePickerETD.Value.HasValue && (this.datePickerETD.Value.Value < DateTime.Now) && (this.datePickerETD_End.Value == null))
+ if((this.datePickerETD.Value != this.Times.EtdBerth) || (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
{
- message = BreCalClient.Resources.Resources.textETDInThePast;
- return false;
- }
-
- if (this.datePickerETD_End.Value.HasValue && this.datePickerETD_End.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textETDInThePast;
- return false;
- }
+ if (this.datePickerETD.Value.IsTooOld() || this.datePickerETD_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textETDInThePast;
+ return false;
+ }
+ }
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
{
@@ -133,17 +128,14 @@ namespace BreCalClient
return false;
}
- if (this.datePickerTidalWindowFrom.Value.HasValue && (this.datePickerTidalWindowFrom.Value.Value < DateTime.Now) && (this.datePickerTidalWindowTo.Value == null))
+ if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
{
- message = BreCalClient.Resources.Resources.textTideTimesInThePast;
- return false;
- }
-
- if (this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowTo.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textTideTimesInThePast;
- return false;
- }
+ if (this.datePickerTidalWindowFrom.Value.IsTooOld() && this.datePickerTidalWindowTo.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textTideTimesInThePast;
+ return false;
+ }
+ }
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
{
diff --git a/src/BreCalClient/EditTimesControl.xaml.cs b/src/BreCalClient/EditTimesControl.xaml.cs
index c2679d4..270df92 100644
--- a/src/BreCalClient/EditTimesControl.xaml.cs
+++ b/src/BreCalClient/EditTimesControl.xaml.cs
@@ -1,11 +1,10 @@
// Copyright (c) 2023 schick Informatik
// Description: Single dialog to edit times for all participant types
// (we might use different controls at a later time)
-//
+//
using BreCalClient.misc.Model;
using System;
-using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Media.Imaging;
using Xceed.Wpf.Toolkit;
@@ -40,7 +39,7 @@ namespace BreCalClient
#region event handler
private void Window_Loaded(object sender, RoutedEventArgs e)
- {
+ {
this.EnableControls();
this.CopyToControls();
}
@@ -49,7 +48,7 @@ namespace BreCalClient
{
if (!CheckValues(out string message))
{
- System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning,
+ System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning,
MessageBoxButton.OK, MessageBoxImage.Warning);
}
else
@@ -58,7 +57,7 @@ namespace BreCalClient
this.DialogResult = true;
this.Close();
}
- }
+ }
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
@@ -99,16 +98,13 @@ namespace BreCalClient
message = "";
- if (this.datePickerETABerth.Value.HasValue && (this.datePickerETABerth.Value.Value < DateTime.Now) && (this.datePickerETABerth_End.Value == null) && (this.datePickerETABerth.Value != this.Times.EtaBerth))
+ if ((this.datePickerETABerth.Value != this.Times.EtaBerth) || (this.datePickerETABerth_End.Value != this.Times.EtaIntervalEnd))
{
- message = BreCalClient.Resources.Resources.textETAInThePast;
- return false;
- }
-
- if (this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth_End.Value < DateTime.Now && this.datePickerETABerth_End.Value != this.Times.EtaIntervalEnd)
- {
- message = BreCalClient.Resources.Resources.textETAInThePast;
- return false;
+ if (this.datePickerETABerth.Value.IsTooOld() || this.datePickerETABerth_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textETAInThePast;
+ return false;
+ }
}
if (this.datePickerETABerth.Value.HasValue && this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth.Value > this.datePickerETABerth_End.Value)
@@ -117,16 +113,13 @@ namespace BreCalClient
return false;
}
- if (this.datePickerETDBerth.Value.HasValue && (this.datePickerETDBerth.Value.Value < DateTime.Now) && (this.datePickerETABerth_End.Value == null) && (this.datePickerETDBerth.Value != this.Times.EtdBerth))
+ if((this.datePickerETDBerth.Value != this.Times.EtdBerth) || (this.datePickerETDBerth_End.Value != this.Times.EtdIntervalEnd))
{
- message = BreCalClient.Resources.Resources.textETDInThePast;
- return false;
- }
-
- if (this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth_End.Value < DateTime.Now && this.datePickerETDBerth_End.Value != this.Times.EtdIntervalEnd)
- {
- message = BreCalClient.Resources.Resources.textETDInThePast;
- return false;
+ if(this.datePickerETDBerth.Value.IsTooOld() || this.datePickerETDBerth_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textETDInThePast;
+ return false;
+ }
}
if (this.datePickerETDBerth.Value.HasValue && this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth.Value > this.datePickerETDBerth_End.Value)
@@ -135,13 +128,13 @@ namespace BreCalClient
return false;
}
- if (this.datePickerLockTime.Value.HasValue && (this.datePickerLockTime.Value.Value < DateTime.Now) && (this.datePickerLockTime.Value != this.Times.LockTime))
+ if (this.datePickerLockTime.Value.IsTooOld() && (this.datePickerLockTime.Value != this.Times.LockTime))
{
message = BreCalClient.Resources.Resources.textLockTimeInThePast;
return false;
}
- if (this.datePickerZoneEntry.Value.HasValue && this.datePickerZoneEntry.Value < DateTime.Now && this.datePickerZoneEntry.Value != this.Times.ZoneEntry)
+ if (this.datePickerZoneEntry.Value.IsTooOld() && (this.datePickerZoneEntry.Value != this.Times.ZoneEntry))
{
message = BreCalClient.Resources.Resources.textZoneEntryInThePast;
return false;
@@ -154,8 +147,7 @@ namespace BreCalClient
return false;
}
- if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) ||
- (this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
+ if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) || (this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
{
message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false;
@@ -218,13 +210,13 @@ namespace BreCalClient
{
this.labelETA.Content = string.Format("ETA {0}", BreCalLists.TimeRefs[displayIndex]);
this.labelETD.Content = string.Format("ETD {0}", BreCalLists.TimeRefs[displayIndex]);
- }
+ }
else
{
this.labelETA.Content = BreCalClient.Resources.Resources.textETABerth;
this.labelETD.Content = BreCalClient.Resources.Resources.textETDBerth;
}
- }
+ }
this.SetLockButton(this.Times.EtaBerthFixed ?? false);
}
@@ -290,11 +282,11 @@ namespace BreCalClient
case Extensions.ParticipantType.PORT_ADMINISTRATION:
this.datePickerLockTime.IsEnabled = true;
break;
- case Extensions.ParticipantType.TUG:
- case Extensions.ParticipantType.PILOT:
- this.datePickerZoneEntry.IsEnabled = (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival);
+ case Extensions.ParticipantType.TUG:
+ case Extensions.ParticipantType.PILOT:
+ this.datePickerZoneEntry.IsEnabled = (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival);
break;
- }
+ }
}
private void SetLockButton(bool newValue)
@@ -311,7 +303,7 @@ namespace BreCalClient
this.imageFixedOrder.Source = new BitmapImage(new Uri(@"pack://application:,,,/Resources/lock_open.png", UriKind.RelativeOrAbsolute));
this.buttonFixedOrder.ToolTip = BreCalClient.Resources.Resources.textTooltipSetFixedOrder;
}
- }
+ }
#endregion
@@ -335,17 +327,17 @@ namespace BreCalClient
private void contextMenuItemClearZoneEntry_Click(object sender, RoutedEventArgs e)
{
this.datePickerZoneEntry.Value = null;
- }
+ }
private void contextMenuItemClearATA_Click(object sender, RoutedEventArgs e)
{
this.datePickerATA.Value = null;
- }
+ }
private void contextMenuItemClearATD_Click(object sender, RoutedEventArgs e)
{
this.datePickerATD.Value = null;
- }
+ }
private void contextMenuItemClearETA_End_Click(object sender, RoutedEventArgs e)
{
@@ -358,6 +350,6 @@ namespace BreCalClient
}
#endregion
-
+
}
}
diff --git a/src/BreCalClient/EditTimesTerminalControl.xaml.cs b/src/BreCalClient/EditTimesTerminalControl.xaml.cs
index e980c9e..368a024 100644
--- a/src/BreCalClient/EditTimesTerminalControl.xaml.cs
+++ b/src/BreCalClient/EditTimesTerminalControl.xaml.cs
@@ -108,17 +108,14 @@ namespace BreCalClient
message = "";
- if (this.datePickerOperationStart.Value.HasValue && (this.datePickerOperationStart.Value.Value < DateTime.Now) && (this.datePickerOperationStart_End.Value == null))
+ if((this.datePickerOperationStart.Value != this.Times.OperationsStart) || (this.datePickerOperationStart_End.Value != this.Times.EtaIntervalEnd))
{
- message = BreCalClient.Resources.Resources.textOperationStartInThePast;
- return false;
- }
-
- if (this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart_End.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textOperationStartInThePast;
- return false;
- }
+ if(this.datePickerOperationStart.Value.IsTooOld() || this.datePickerOperationStart_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textOperationStartInThePast;
+ return false;
+ }
+ }
if (this.datePickerOperationStart.Value.HasValue && this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart.Value > this.datePickerOperationStart_End.Value)
{
@@ -126,17 +123,14 @@ namespace BreCalClient
return false;
}
- if (this.datePickerOperationEnd.Value.HasValue && (this.datePickerOperationEnd.Value.Value < DateTime.Now) && (this.datePickerOperationEnd_End.Value == null))
+ if ((this.datePickerOperationEnd.Value != this.Times.OperationsEnd) || (this.datePickerOperationEnd_End.Value != this.Times.EtdIntervalEnd))
{
- message = BreCalClient.Resources.Resources.textOperationEndInThePast;
- return false;
- }
-
- if (this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd_End.Value < DateTime.Now)
- {
- message = BreCalClient.Resources.Resources.textOperationEndInThePast;
- return false;
- }
+ if(this.datePickerOperationEnd.Value.IsTooOld() || this.datePickerOperationEnd_End.Value.IsTooOld())
+ {
+ message = BreCalClient.Resources.Resources.textOperationEndInThePast;
+ return false;
+ }
+ }
if (this.datePickerOperationEnd.Value.HasValue && this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd.Value > this.datePickerOperationEnd_End.Value)
{
@@ -150,8 +144,7 @@ namespace BreCalClient
return false;
}
- if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) ||
- (this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
+ if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) || (this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
{
message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false;
diff --git a/src/BreCalClient/Extensions.cs b/src/BreCalClient/Extensions.cs
index 54fedb3..f4ba524 100644
--- a/src/BreCalClient/Extensions.cs
+++ b/src/BreCalClient/Extensions.cs
@@ -69,6 +69,14 @@ namespace BreCalClient
return datetime > DateTime.Now.AddYears(1);
}
+ public static bool IsTooOld(this DateTime? datetime)
+ {
+ if (datetime == null) return false;
+ {
+ return datetime < DateTime.Now.AddDays(-1);
+ }
+ }
+
public static bool IsTypeFlagSet(this Participant participant, ParticipantType flag)
{
return (participant.Type & (uint)flag) != 0;
diff --git a/src/server/BreCal/validators/input_validation.py b/src/server/BreCal/validators/input_validation.py
index cc97ccb..075a51d 100644
--- a/src/server/BreCal/validators/input_validation.py
+++ b/src/server/BreCal/validators/input_validation.py
@@ -28,7 +28,7 @@ def validation_error_default_asserts(response):
def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict):
"""this function applies more complex validation functions to data, which is sent to a post-request of shipcalls"""
# DEPRECATED: this function has been refactored into InputValidationShipcall (see methods for POST and PUT evaluation)
- # #TODO_refactor: this function is pretty complex. One may instead build an object, which calls the methods separately.
+ # #TODO_refactor: this function is pretty complex. One may instead build an object, which calls the methods separately.
##### Section 1: check user_data #####
# check, whether the user belongs to a participant, which is of type ParticipantType.BSMD
@@ -36,23 +36,23 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
is_bsmd = check_if_user_is_bsmd_type(user_data)
if not is_bsmd:
raise ValidationError({"user_participant_type":f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}"})
-
+
##### Section 2: check loadedModel #####
valid_ship_id = check_if_ship_id_is_valid(ship_id=loadedModel.get("ship_id", None))
if not valid_ship_id:
raise ValidationError({"ship_id":f"provided an invalid ship id, which is not found in the database: {loadedModel.get('ship_id', None)}"})
-
+
valid_arrival_berth_id = check_if_berth_id_is_valid(berth_id=loadedModel.get("arrival_berth_id", None))
if not valid_arrival_berth_id:
raise ValidationError({"arrival_berth_id":f"provided an invalid arrival berth id, which is not found in the database: {loadedModel.get('arrival_berth_id', None)}"})
-
+
valid_departure_berth_id = check_if_berth_id_is_valid(berth_id=loadedModel.get("departure_berth_id", None))
if not valid_departure_berth_id:
raise ValidationError({"departure_berth_id":f"provided an invalid departure berth id, which is not found in the database: {loadedModel.get('departure_berth_id', None)}"})
-
+
valid_participant_ids = check_if_participant_ids_are_valid(participants=loadedModel.get("participants",[]))
if not valid_participant_ids:
- raise ValidationError({"participants":f"one of the provided participant ids is invalid. Could not find one of these in the database: {loadedModel.get('participants', None)}"})
+ raise ValidationError({"participants":f"one of the provided participant ids is invalid. Could not find one of these in the database: {loadedModel.get('participants', None)}"})
##### Section 3: check content #####
@@ -63,18 +63,18 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
value = content.get(forbidden_key, None)
if value is not None:
raise ValidationError({"forbidden_key":f"'{forbidden_key}' may not be set on POST. Found: {value}"})
-
+
voyage_str_is_invalid = check_if_string_has_special_characters(text=content.get("voyage",""))
if voyage_str_is_invalid:
- raise ValidationError({"voyage":f"there are invalid characters in the 'voyage'-string. Please use only digits and ASCII letters. Allowed: {ascii_letters+digits}. Found: {content.get('voyage')}"})
-
+ raise ValidationError({"voyage":f"there are invalid characters in the 'voyage'-string. Please use only digits and ASCII letters. Allowed: {ascii_letters+digits}. Found: {content.get('voyage')}"})
+
##### Section 4: check loadedModel & content #####
# #TODO_refactor: these methods should be placed in separate locations
# existance checks in content
- # datetime checks in loadedModel (datetime.datetime objects). Dates should be in the future.
- time_now = datetime.datetime.now()
+ # datetime checks in loadedModel (datetime.datetime objects). Dates should be in the future.
+ time_now = datetime.datetime.now() - datetime.timedelta(days=1)
type_ = loadedModel.get("type", int(ShipcallType.undefined))
if int(type_)==int(ShipcallType.undefined):
raise ValidationError({"type":f"providing 'type' is mandatory. Missing key!"})
@@ -85,7 +85,7 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
if content.get("arrival_berth_id", None) is None:
raise ValidationError({"arrival_berth_id":f"providing 'arrival_berth_id' is mandatory. Missing key!"})
if not eta >= time_now:
- raise ValidationError({"eta":f"'eta' must be in the future. Incorrect datetime provided."})
+ raise ValidationError({"eta":f"'eta' is too far in the past. Incorrect datetime provided."})
elif int(type_)==int(ShipcallType.departure):
etd = loadedModel.get("etd")
if (content.get("etd", None) is None):
@@ -93,7 +93,7 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
if content.get("departure_berth_id", None) is None:
raise ValidationError({"departure_berth_id":f"providing 'departure_berth_id' is mandatory. Missing key!"})
if not etd >= time_now:
- raise ValidationError({"etd":f"'etd' must be in the future. Incorrect datetime provided."})
+ raise ValidationError({"etd":f"'etd' is too far in the past. Incorrect datetime provided."})
elif int(type_)==int(ShipcallType.shifting):
eta = loadedModel.get("eta")
etd = loadedModel.get("etd")
@@ -103,20 +103,20 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
if (content.get("arrival_berth_id", None) is None) or (content.get("departure_berth_id", None) is None):
raise ValidationError({"arrival_berth_id_or_departure_berth_id":f"providing 'arrival_berth_id' & 'departure_berth_id' is mandatory. Missing key!"})
if (not eta >= time_now) or (not etd >= time_now) or (not eta >= etd):
- raise ValidationError({"eta_or_etd":f"'eta' and 'etd' must be in the future. Incorrect datetime provided."})
-
+ raise ValidationError({"eta_or_etd":f"'eta' and 'etd' are too far in the past. Incorrect datetime provided."})
+
tidal_window_from = loadedModel.get("tidal_window_from", None)
tidal_window_to = loadedModel.get("tidal_window_to", None)
if tidal_window_to is not None:
if not tidal_window_to >= time_now:
- raise ValidationError({"tidal_window_to":f"'tidal_window_to' must be in the future. Incorrect datetime provided."})
+ raise ValidationError({"tidal_window_to":f"'tidal_window_to' is too far in the past. Incorrect datetime provided."})
if tidal_window_from is not None:
if not tidal_window_from >= time_now:
- raise ValidationError({"tidal_window_from":f"'tidal_window_from' must be in the future. Incorrect datetime provided."})
-
+ raise ValidationError({"tidal_window_from":f"'tidal_window_from' is too far in the past. Incorrect datetime provided."})
+
# #TODO: assert tidal_window_from > tidal_window_to
-
+
# #TODO: len of participants > 0, if agency
# * assigned participant for agency
return
@@ -126,21 +126,21 @@ class InputValidation():
def __init__(self):
self.build_supported_models_dictionary()
return
-
+
def build_supported_models_dictionary(self):
self.supported_models = {
Ship:ShipValidation(),
Shipcall:ShipcallValidation(),
- Berth:BerthValidation(),
- User:UserValidation(),
+ Berth:BerthValidation(),
+ User:UserValidation(),
Participant:ParticipantValidation(),
}
return
-
+
def assert_if_not_supported(self, dataclass_object):
assert type(dataclass_object) in self.supported_models, f"unsupported model. Found: {type(dataclass_object)}"
return
-
+
def verify(self, dataclass_object):
self.assert_if_not_supported(dataclass_object)
@@ -157,17 +157,17 @@ class DataclassValidation(ABC):
"""parent class of dataclas validators, which determines the outline of every object"""
def __init__(self):
return
-
+
def check(self, dataclass_object) -> (list, bool):
"""
- the 'check' method provides a default style, how each dataclass object is validated. It returns a list of violations
+ the 'check' method provides a default style, how each dataclass object is validated. It returns a list of violations
and a boolean, which determines, whether the check is passed successfully
"""
all_rules = self.apply_all_rules(dataclass_object)
violations = self.filter_violations(all_rules)
input_validation_state = self.evaluate(violations)
return (violations, input_validation_state)
-
+
@abstractmethod
def apply_all_rules(self, dataclass_object) -> list:
"""
@@ -176,13 +176,13 @@ class DataclassValidation(ABC):
"""
all_rules = [(True, 'blank_validation_rule')]
return all_rules
-
+
def filter_violations(self, all_rules):
"""input: all_rules, a list of tuples, where each element is (output, validation_name), which are (bool, str). """
# if output is False, a violation is observed
violations = [result[1] for result in all_rules if not result[0]]
return violations
-
+
def evaluate(self, violations) -> bool:
input_validation_state = len(violations)==0
return input_validation_state
@@ -194,7 +194,7 @@ class ShipcallValidation(DataclassValidation):
def __init__(self):
super().__init__()
return
-
+
def apply_all_rules(self, dataclass_object) -> list:
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
raise NotImplementedError()
@@ -202,16 +202,16 @@ class ShipcallValidation(DataclassValidation):
from BreCal.validators.schema_validation import ship_bollard_pull_is_defined_or_is_not_tug, ship_bollard_pull_is_none_or_in_range, ship_callsign_len_is_seven_at_maximum, ship_eni_len_is_eight, ship_imo_len_is_seven, ship_length_in_range, ship_participant_id_is_defined_or_is_not_tug, ship_participant_id_is_none_or_int, ship_width_in_range
-# skip: ship_max_draft_is_defined_or_is_not_tug, ship_max_draft_is_none_or_in_range,
+# skip: ship_max_draft_is_defined_or_is_not_tug, ship_max_draft_is_none_or_in_range,
class ShipValidation(DataclassValidation):
"""an object that validates a Ship dataclass object"""
def __init__(self):
super().__init__()
return
-
+
def apply_all_rules(self, dataclass_object) -> list:
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
- # skip: ship_max_draft_is_defined_or_is_not_tug, ship_max_draft_is_none_or_in_range,
+ # skip: ship_max_draft_is_defined_or_is_not_tug, ship_max_draft_is_none_or_in_range,
"""
#TODO_ship_max_draft
with pytest.raises(AttributeError, match="'Ship' object has no attribute 'max_draft'"):
@@ -225,14 +225,14 @@ class ShipValidation(DataclassValidation):
check_rule(dataclass_object)
for check_rule in [
- ship_bollard_pull_is_defined_or_is_not_tug,
- ship_bollard_pull_is_none_or_in_range,
- ship_callsign_len_is_seven_at_maximum,
- ship_eni_len_is_eight,
- ship_imo_len_is_seven,
- ship_length_in_range,
- ship_participant_id_is_defined_or_is_not_tug,
- ship_participant_id_is_none_or_int,
+ ship_bollard_pull_is_defined_or_is_not_tug,
+ ship_bollard_pull_is_none_or_in_range,
+ ship_callsign_len_is_seven_at_maximum,
+ ship_eni_len_is_eight,
+ ship_imo_len_is_seven,
+ ship_length_in_range,
+ ship_participant_id_is_defined_or_is_not_tug,
+ ship_participant_id_is_none_or_int,
ship_width_in_range
]
]
@@ -243,7 +243,7 @@ class BerthValidation(DataclassValidation):
def __init__(self):
super().__init__()
return
-
+
def apply_all_rules(self, dataclass_object) -> list:
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
raise NotImplementedError()
@@ -254,7 +254,7 @@ class UserValidation(DataclassValidation):
def __init__(self):
super().__init__()
return
-
+
def apply_all_rules(self, dataclass_object) -> list:
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
raise NotImplementedError()
@@ -266,7 +266,7 @@ class ParticipantValidation(DataclassValidation):
def __init__(self):
super().__init__()
return
-
+
def apply_all_rules(self, dataclass_object) -> list:
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
diff --git a/src/server/BreCal/validators/input_validation_shipcall.py b/src/server/BreCal/validators/input_validation_shipcall.py
index 52e380f..39c200e 100644
--- a/src/server/BreCal/validators/input_validation_shipcall.py
+++ b/src/server/BreCal/validators/input_validation_shipcall.py
@@ -124,11 +124,14 @@ class InputValidationShipcall():
if check_if_int_is_valid_flag(flags_value, enum_object=ParticipantFlag):
raise ValidationError({"flags":f"incorrect value provided for 'flags'. Must be a valid combination of the flags."})
+ existing_shipcall = None
if is_put_data:
+
+ existing_shipcall = InputValidationShipcall.get_shipcall_by_id(loadedModel.get("id"))
# the type of a shipcall may not be changed. It can only be set with the initial POST-request.
- InputValidationShipcall.check_shipcall_type_is_unchanged(loadedModel)
-
- InputValidationShipcall.check_times_are_in_future(loadedModel, content)
+ InputValidationShipcall.check_shipcall_type_is_unchanged(loadedModel, existing_shipcall)
+
+ InputValidationShipcall.check_times_are_in_future(loadedModel, content, existing_shipcall)
# some arguments must not be provided
InputValidationShipcall.check_forbidden_arguments(content, forbidden_keys=forbidden_keys)
@@ -255,15 +258,17 @@ class InputValidationShipcall():
raise ValidationError({"participants":f"every participant id and type should be listed only once. Found multiple entries for one of the participants."})
@staticmethod
- def check_shipcall_type_is_unchanged(loadedModel:dict):
- # the type of a shipcall may only be set on POST requests. Afterwards, shipcall types may not be changed.
- query = SQLQuery.get_shipcall_by_id()
- shipcall = execute_sql_query_standalone(query=query, model=Shipcall, param={"id":loadedModel.get("id")}, command_type="single")
-
- if int(loadedModel["type"]) != int(shipcall.type):
+ def check_shipcall_type_is_unchanged(loadedModel:dict, existing_shipcall:object):
+ if int(loadedModel["type"]) != int(existing_shipcall.type):
raise ValidationError({"type":f"The shipcall type may only be set in the initial POST-request. Afterwards, changing the shipcall type is not allowed."}) # @pytest.raises
return
+ @staticmethod
+ def get_shipcall_by_id(shipcall_id:int):
+ query = SQLQuery.get_shipcall_by_id()
+ shipcall = execute_sql_query_standalone(query=query, model=Shipcall, param={"id":shipcall_id}, command_type="single")
+ return shipcall
+
@staticmethod
def check_forbidden_arguments(content:dict, forbidden_keys=["evaluation", "evaluation_message"]):
"""
@@ -324,13 +329,13 @@ class InputValidationShipcall():
return
@staticmethod
- def check_times_are_in_future(loadedModel:dict, content:dict):
+ def check_times_are_in_future(loadedModel:dict, content:dict, existing_shipcall:object):
"""
Dates should be in the future. Depending on the ShipcallType, specific values should be checked
- Perfornms datetime checks in the loadedModel (datetime.datetime objects).
+ Performs datetime checks in the loadedModel (datetime.datetime objects).
"""
- # obtain the current datetime to check, whether the provided values are in the future
- time_now = datetime.datetime.now()
+ # obtain the current datetime to check, whether the provided values are after ref time
+ time_ref = datetime.datetime.now() - datetime.timedelta(days=1)
type_ = loadedModel.get("type", ShipcallType.undefined.name)
if isinstance(type_, str): # convert the name string to a ShipcallType data model
@@ -346,16 +351,29 @@ class InputValidationShipcall():
etd = loadedModel.get("etd")
tidal_window_from = loadedModel.get("tidal_window_from", None)
tidal_window_to = loadedModel.get("tidal_window_to", None)
+ existing_eta = None
+ existing_etd = None
+ existing_tidal_window_from = None
+ existing_tidal_window_to = None
- # Estimated arrival or departure times
- InputValidationShipcall.check_times_in_future_based_on_type(type_, time_now, eta, etd)
+ if existing_shipcall is not None:
+ existing_eta = existing_shipcall.eta
+ existing_etd = existing_shipcall.etd
+ existing_tidal_window_from = existing_shipcall.tidal_window_from
+ existing_tidal_window_to = existing_shipcall.tidal_window_to
+
+ if eta != existing_eta or etd != existing_etd:
+ # Estimated arrival or departure times
+ InputValidationShipcall.check_times_in_future_based_on_type(type_, time_ref, eta, etd)
+
+ if tidal_window_from != existing_tidal_window_from or tidal_window_to != existing_tidal_window_to:
+ # Tidal Window
+ InputValidationShipcall.check_tidal_window_in_future(type_, time_ref, tidal_window_from, tidal_window_to)
- # Tidal Window
- InputValidationShipcall.check_tidal_window_in_future(type_, time_now, tidal_window_from, tidal_window_to)
return
@staticmethod
- def check_times_in_future_based_on_type(type_, time_now, eta, etd):
+ def check_times_in_future_based_on_type(type_, time_ref, eta, etd):
"""
checks, whether the ETA & ETD times are in the future.
based on the type, this function checks:
@@ -365,8 +383,8 @@ class InputValidationShipcall():
"""
if (eta is None) and (etd is None):
return
-
- time_in_a_year = time_now.replace(time_now.year + 1)
+
+ time_in_a_year = datetime.datetime.now().replace(datetime.datetime.now().year + 1)
if type_ is None:
raise ValidationError({"type":f"when providing 'eta' or 'etd', one must provide the type of the shipcall, so the datetimes can be verified."})
@@ -381,8 +399,8 @@ class InputValidationShipcall():
if eta is None: # null values -> no violation
return
- if not eta > time_now:
- raise ValidationError({"eta":f"'eta' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}."})
+ if not eta > time_ref:
+ raise ValidationError({"eta":f"'eta' is too far in the past. Incorrect datetime provided. Current Time: {time_ref}. ETA: {eta}."})
if etd is not None:
raise ValidationError({"etd":f"'etd' should not be set when the shipcall type is 'arrival'."})
if eta > time_in_a_year:
@@ -392,8 +410,9 @@ class InputValidationShipcall():
if etd is None: # null values -> no violation
return
- if not etd > time_now:
- raise ValidationError({"etd":f"'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETD: {etd}."})
+ if not etd > time_ref:
+ raise ValidationError({"etd":f"'etd' is too far in the past. Incorrect datetime provided. Current Time: {time_ref}. ETD: {etd}."})
+
if eta is not None:
raise ValidationError({"eta":f"'eta' should not be set when the shipcall type is 'departure'."})
if etd > time_in_a_year:
@@ -408,8 +427,8 @@ class InputValidationShipcall():
# rules, a user is only allowed to provide *both* values.
raise ValidationError({"eta_or_etd":f"For shifting shipcalls one should always provide, both, eta and etd."})
- if (not eta > time_now) or (not etd > time_now):
- raise ValidationError({"eta_or_etd":f"'eta' and 'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}. ETD: {etd}"})
+ if (not eta > time_ref) or (not etd > time_ref):
+ raise ValidationError({"eta_or_etd":f"'eta' and 'etd' is too far in the past. Incorrect datetime provided. Current Time: {time_ref}. ETA: {eta}. ETD: {etd}"})
if (not etd < eta):
raise ValidationError({"eta_or_etd":f"The estimated time of departure ('etd') must take place *before the estimated time of arrival ('eta'). The ship cannot arrive, before it has departed. Found: ETD: {etd}, ETA: {eta}"})
@@ -419,30 +438,29 @@ class InputValidationShipcall():
raise ValidationError({"eta":f"'eta' is more than a year in the future. ETA: {eta}."})
if etd > time_in_a_year:
raise ValidationError({"etd":f"'etd' is more than a year in the future. ETD: {etd}."})
-
+
return
@staticmethod
- def check_tidal_window_in_future(type_, time_now, tidal_window_from, tidal_window_to):
-
- time_in_a_year = time_now.replace(time_now.year + 1)
+ def check_tidal_window_in_future(type_, time_ref, tidal_window_from, tidal_window_to):
+ time_in_a_year = datetime.datetime.now().replace(datetime.datetime.now().year + 1)
if tidal_window_to is not None:
- if not tidal_window_to >= time_now:
- raise ValidationError({"tidal_window_to":f"'tidal_window_to' must be in the future. Incorrect datetime provided."})
+ if not tidal_window_to >= time_ref:
+ raise ValidationError({"tidal_window_to":f"'tidal_window_to' is too far in the past. Incorrect datetime provided."})
if tidal_window_to > time_in_a_year:
raise ValidationError({"tidal_window_to":f"'tidal_window_to' is more than a year in the future. Found: {tidal_window_to}."})
if tidal_window_from is not None:
- if not tidal_window_from >= time_now:
- raise ValidationError({"tidal_window_from":f"'tidal_window_from' must be in the future. Incorrect datetime provided."})
+ if not tidal_window_from >= time_ref:
+ raise ValidationError({"tidal_window_from":f"'tidal_window_from' is too far in the past. Incorrect datetime provided."})
if tidal_window_from > time_in_a_year:
raise ValidationError({"tidal_window_from":f"'tidal_window_from' is more than a year in the future. Found: {tidal_window_from}."})
if (tidal_window_to is not None) and (tidal_window_from is not None):
if tidal_window_to < tidal_window_from:
raise ValidationError({"tidal_window_to_or_tidal_window_from":f"'tidal_window_to' must take place after 'tidal_window_from'. Incorrect datetime provided. Found 'tidal_window_to': {tidal_window_to}, 'tidal_window_from': {tidal_window_to}."})
-
+
if (tidal_window_to is not None and tidal_window_from is None) or (tidal_window_to is None and tidal_window_from is not None):
raise ValidationError({"tidal_window_to_or_tidal_window_from":f"'tidal_window_to' and 'tidal_window_from' must both be provided."})
diff --git a/src/server/BreCal/validators/input_validation_times.py b/src/server/BreCal/validators/input_validation_times.py
index 9db0a2c..4b5dad9 100644
--- a/src/server/BreCal/validators/input_validation_times.py
+++ b/src/server/BreCal/validators/input_validation_times.py
@@ -414,6 +414,8 @@ class InputValidationTimes():
# commonly used in the PUT-request
if loadedModel is not None:
(shipcall_id, times_assigned_participant) = InputValidationTimes.prepare_authority_check_for_put_request(loadedModel)
+ else:
+ loadedModel = get_times_data_for_id(times_id)
# commonly used in the DELETE-request
if times_id is not None:
diff --git a/src/server/tests/validators/test_input_validation_shipcall.py b/src/server/tests/validators/test_input_validation_shipcall.py
index 87b3b7f..0e48f55 100644
--- a/src/server/tests/validators/test_input_validation_shipcall.py
+++ b/src/server/tests/validators/test_input_validation_shipcall.py
@@ -207,7 +207,7 @@ def test_shipcall_post_request_fails_when_voyage_string_is_invalid(get_stub_toke
with pytest.raises(ValidationError, match="Longer than maximum length 16"):
assert response.status_code==400
raise ValidationError(response.json())
-
+
# Fail: special characters
post_data = original_post_data.copy()
post_data["voyage"] = '👽'
@@ -226,17 +226,17 @@ def test_shipcall_post_request_fails_when_type_arrival_and_not_in_future(get_stu
# accept
post_data = original_post_data.copy()
post_data["type"] = ShipcallType.arrival.name
- post_data["eta"] = (datetime.datetime.now() + datetime.timedelta(hours=3)).isoformat()
+ post_data["eta"] = (datetime.datetime.now() + datetime.timedelta(days=2)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
assert response.status_code == 201
# error
post_data = original_post_data.copy()
post_data["type"] = ShipcallType.arrival.name
- post_data["eta"] = (datetime.datetime.now() - datetime.timedelta(hours=3)).isoformat()
+ post_data["eta"] = (datetime.datetime.now() - datetime.timedelta(days=2)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
- with pytest.raises(ValidationError, match="must be in the future. Incorrect datetime provided"):
+ with pytest.raises(ValidationError, match="is too far in the past. Incorrect datetime provided"):
assert response.status_code==400
raise ValidationError(response.json())
return
@@ -256,10 +256,10 @@ def test_shipcall_post_request_fails_when_type_departure_and_not_in_future(get_s
# error
post_data = original_post_data.copy()
post_data["type"] = ShipcallType.departure.name
- post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(hours=3)).isoformat()
+ post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(days=3)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
- with pytest.raises(ValidationError, match="must be in the future. Incorrect datetime provided"):
+ with pytest.raises(ValidationError, match="is too far in the past. Incorrect datetime provided"):
assert response.status_code==400
raise ValidationError(response.json())
return
@@ -280,11 +280,11 @@ def test_shipcall_post_request_fails_when_type_shifting_and_not_in_future(get_st
# error
post_data = original_post_data.copy()
post_data["type"] = ShipcallType.shifting.name
- post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(hours=3)).isoformat()
+ post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(days=3)).isoformat()
post_data["eta"] = (datetime.datetime.now() + datetime.timedelta(hours=3,minutes=1)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
- with pytest.raises(ValidationError, match="must be in the future. Incorrect datetime provided"):
+ with pytest.raises(ValidationError, match="is too far in the past. Incorrect datetime provided"):
assert response.status_code==400
raise ValidationError(response.json())
return
@@ -629,7 +629,7 @@ def test_shipcall_put_request_fails_when_different_participant_id_is_assigned(ge
{"id":99115, 'participant_id': 5, 'type': 8}]
spm_shipcall_data = [
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
- for spm in
+ for spm in
spm_shipcall_data
]
spm_shipcall_data = [ShipcallParticipantMap(**spm) for spm in spm_shipcall_data]
@@ -652,7 +652,7 @@ def test_shipcall_put_request_success(get_shipcall_id_after_stub_post_request):
user_data = {'id':6, 'participant_id':1}
loadedModel = post_data
content = post_data
-
+
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
modified = datetime.datetime.now()+datetime.timedelta(minutes=2)
@@ -662,7 +662,7 @@ def test_shipcall_put_request_success(get_shipcall_id_after_stub_post_request):
{"id":99115, 'participant_id': 5, 'type': 8}]
spm_shipcall_data = [
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
- for spm in
+ for spm in
spm_shipcall_data
]
spm_shipcall_data = [ShipcallParticipantMap(**spm) for spm in spm_shipcall_data]
@@ -687,7 +687,7 @@ def test_shipcall_put_request_fails_when_no_agency_is_assigned(get_shipcall_id_a
user_data = {'id':6, 'participant_id':2} # participant_id 2 is not BSMD and is not authorized.
loadedModel = post_data
content = post_data
-
+
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
modified = datetime.datetime.now()+datetime.timedelta(minutes=2)
@@ -697,7 +697,7 @@ def test_shipcall_put_request_fails_when_no_agency_is_assigned(get_shipcall_id_a
{"id":99115, 'participant_id': 5, 'type': 4}]
spm_shipcall_data = [
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
- for spm in
+ for spm in
spm_shipcall_data
]
spm_shipcall_data = [ShipcallParticipantMap(**spm) for spm in spm_shipcall_data]
@@ -705,7 +705,7 @@ def test_shipcall_put_request_fails_when_no_agency_is_assigned(get_shipcall_id_a
# no agency assigned
ivs = InputValidationShipcall()
-
+
with pytest.raises(werkzeug.exceptions.Forbidden, match=re.escape(f"PUT Requests for shipcalls can only be issued by an assigned AGENCY or BSMD users (if the special-flag is enabled). There is no assigned agency yet, so only BSMD users can change datasets.")):
ivs.check_user_is_authorized_for_put_request(user_data, loadedModel, content, spm_shipcall_data)
return
@@ -730,7 +730,7 @@ def test_shipcall_put_request_fails_when_user_is_not_authorized(get_shipcall_id_
{"id":99115, 'participant_id': 5, 'type': 4}]
spm_shipcall_data = [
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
- for spm in
+ for spm in
spm_shipcall_data
]
spm_shipcall_data = [ShipcallParticipantMap(**spm) for spm in spm_shipcall_data]
@@ -754,20 +754,20 @@ def test_shipcall_put_request_fails_when_user_tries_self_assignment(get_shipcall
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
modified = datetime.datetime.now()+datetime.timedelta(minutes=2)
-
+
spm_shipcall_data = [
{"id":99113, 'participant_id': 3, 'type': 1},
{"id":99114, 'participant_id': 4, 'type': 2},
{"id":99115, 'participant_id': 5, 'type': 4}]
spm_shipcall_data = [
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
- for spm in
+ for spm in
spm_shipcall_data
]
spm_shipcall_data = [ShipcallParticipantMap(**spm) for spm in spm_shipcall_data]
- # self-assignment. User is participant 6, and wants to assign participant 6.
+ # self-assignment. User is participant 6, and wants to assign participant 6.
ivs = InputValidationShipcall()
with pytest.raises(werkzeug.exceptions.Forbidden, match=re.escape("PUT Requests for shipcalls can only be issued by an assigned AGENCY or BSMD users (if the special-flag is enabled). There is no assigned agency yet, so only BSMD users can change datasets.")):
# previous error message: An agency cannot self-register for a shipcall. The request is issued by an agency-user and tries to assign an AGENCY as the participant of the shipcall.""
@@ -813,7 +813,7 @@ def test_shipcall_put_request_works_if_most_values_are_null():
InputValidationShipcall.evaluate_put_data(user_data, loadedModel, content)
return
-
+
@@ -860,10 +860,10 @@ def test_shipcall_put_request_fails_input_validation_shipcall_when_shipcall_is_c
return
def test_post_data_with_valid_data(get_stub_token):
- """This unit test uses the input data from
+ """This unit test uses the input data from
# https://trello.com/c/VXVSLTF4/267-shipcall-anlegen-shifting-erh%C3%A4lt-fehler-aufgrund-fr%C3%BCherem-etd-als-eta
- to make sure, the failure case no longer appears.
+ to make sure, the failure case no longer appears.
"""
url, token = get_stub_token["url"], get_stub_token["token"]