Merge branch 'feature/extra_time_logic' into release/1.5.0
This commit is contained in:
commit
4870c81783
@ -8,8 +8,8 @@
|
|||||||
<SignAssembly>True</SignAssembly>
|
<SignAssembly>True</SignAssembly>
|
||||||
<StartupObject>BreCalClient.App</StartupObject>
|
<StartupObject>BreCalClient.App</StartupObject>
|
||||||
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
|
||||||
<AssemblyVersion>1.5.0.8</AssemblyVersion>
|
<AssemblyVersion>1.5.0.12</AssemblyVersion>
|
||||||
<FileVersion>1.5.0.8</FileVersion>
|
<FileVersion>1.5.0.12</FileVersion>
|
||||||
<Title>Bremen calling client</Title>
|
<Title>Bremen calling client</Title>
|
||||||
<Description>A Windows WPF client for the Bremen calling API.</Description>
|
<Description>A Windows WPF client for the Bremen calling API.</Description>
|
||||||
<ApplicationIcon>containership.ico</ApplicationIcon>
|
<ApplicationIcon>containership.ico</ApplicationIcon>
|
||||||
|
|||||||
@ -204,26 +204,22 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
case ShipcallType.Departure:
|
case ShipcallType.Departure:
|
||||||
isEnabled &= this.comboBoxDepartureBerth.SelectedItem != null;
|
isEnabled &= this.comboBoxDepartureBerth.SelectedItem != null;
|
||||||
isEnabled &= this.datePickerETD.Value.HasValue;
|
isEnabled &= this.datePickerETD.Value.HasValue;
|
||||||
if(this.datePickerETD.Value.HasValue)
|
isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
|
||||||
isEnabled &= (this.datePickerETD.Value.Value > DateTime.Now);
|
|
||||||
isEnabled &= !this.datePickerETD.Value.IsTooFar();
|
isEnabled &= !this.datePickerETD.Value.IsTooFar();
|
||||||
break;
|
break;
|
||||||
case ShipcallType.Arrival:
|
case ShipcallType.Arrival:
|
||||||
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
|
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
|
||||||
isEnabled &= this.datePickerETA.Value.HasValue;
|
isEnabled &= this.datePickerETA.Value.HasValue;
|
||||||
if(this.datePickerETA.Value.HasValue)
|
isEnabled &= !(this.datePickerETA.Value.IsTooOld() && this.datePickerETA.Value != this.ShipcallModel.Shipcall?.Eta);
|
||||||
isEnabled &= (this.datePickerETA.Value.Value > DateTime.Now);
|
|
||||||
isEnabled &= !this.datePickerETA.Value.IsTooFar();
|
isEnabled &= !this.datePickerETA.Value.IsTooFar();
|
||||||
break;
|
break;
|
||||||
case ShipcallType.Shifting:
|
case ShipcallType.Shifting:
|
||||||
isEnabled &= ((this.comboBoxDepartureBerth.SelectedItem != null) && (this.comboBoxArrivalBerth.SelectedItem != null));
|
isEnabled &= ((this.comboBoxDepartureBerth.SelectedItem != null) && (this.comboBoxArrivalBerth.SelectedItem != null));
|
||||||
isEnabled &= this.datePickerETD.Value.HasValue;
|
isEnabled &= this.datePickerETD.Value.HasValue;
|
||||||
isEnabled &= this.datePickerETA.Value.HasValue;
|
isEnabled &= this.datePickerETA.Value.HasValue;
|
||||||
if (this.datePickerETD.Value.HasValue)
|
isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
|
||||||
isEnabled &= (this.datePickerETD.Value.Value > DateTime.Now);
|
isEnabled &= !(this.datePickerETA.Value.IsTooOld() && this.datePickerETA.Value != this.ShipcallModel.Shipcall?.Eta);
|
||||||
if (this.datePickerETA.Value.HasValue)
|
|
||||||
isEnabled &= (this.datePickerETA.Value.Value > DateTime.Now);
|
|
||||||
if (this.datePickerETA.Value.HasValue && this.datePickerETD.Value.HasValue)
|
if (this.datePickerETA.Value.HasValue && this.datePickerETD.Value.HasValue)
|
||||||
isEnabled &= (this.datePickerETA.Value.Value > this.datePickerETD.Value.Value);
|
isEnabled &= (this.datePickerETA.Value.Value > this.datePickerETD.Value.Value);
|
||||||
isEnabled &= !this.datePickerETD.Value.IsTooFar();
|
isEnabled &= !this.datePickerETD.Value.IsTooFar();
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using static BreCalClient.Extensions;
|
using static BreCalClient.Extensions;
|
||||||
|
|
||||||
@ -97,47 +96,41 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
message = "";
|
message = "";
|
||||||
|
|
||||||
if (this.datePickerETA.Value.HasValue && (this.datePickerETA.Value.Value < DateTime.Now) && (this.datePickerETA_End.Value == null))
|
if ((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd)) // something has changed
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
if (datePickerETA.Value.IsTooOld() || datePickerETA_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
|
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;
|
if(datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowTo.Value < DateTime.Now)
|
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
if ((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
message = BreCalClient.Resources.Resources.textTidalBothValues;
|
||||||
return false;
|
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())
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) ||
|
if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
||||||
(this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -4,15 +4,8 @@
|
|||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls.Primitives;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using Xceed.Wpf.Toolkit;
|
|
||||||
using static BreCalClient.Extensions;
|
using static BreCalClient.Extensions;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace BreCalClient
|
namespace BreCalClient
|
||||||
{
|
{
|
||||||
@ -107,17 +100,14 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
message = "";
|
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;
|
if (datePickerETD.Value.IsTooOld() || datePickerETD_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
|
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;
|
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;
|
if (this.datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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)
|
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||||
{
|
{
|
||||||
@ -155,8 +142,7 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) ||
|
if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
||||||
(this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -97,17 +97,15 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
message = "";
|
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;
|
if (this.datePickerETA.Value.IsTooOld() && this.datePickerETA_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
|
||||||
{
|
{
|
||||||
@ -115,17 +113,14 @@ namespace BreCalClient
|
|||||||
return false;
|
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;
|
if (this.datePickerETD.Value.IsTooOld() || this.datePickerETD_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
|
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;
|
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;
|
if (this.datePickerTidalWindowFrom.Value.IsTooOld() && this.datePickerTidalWindowTo.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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)
|
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
// Copyright (c) 2023 schick Informatik
|
// Copyright (c) 2023 schick Informatik
|
||||||
// Description: Single dialog to edit times for all participant types
|
// Description: Single dialog to edit times for all participant types
|
||||||
// (we might use different controls at a later time)
|
// (we might use different controls at a later time)
|
||||||
//
|
//
|
||||||
|
|
||||||
using BreCalClient.misc.Model;
|
using BreCalClient.misc.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using Xceed.Wpf.Toolkit;
|
using Xceed.Wpf.Toolkit;
|
||||||
@ -40,7 +39,7 @@ namespace BreCalClient
|
|||||||
#region event handler
|
#region event handler
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.EnableControls();
|
this.EnableControls();
|
||||||
this.CopyToControls();
|
this.CopyToControls();
|
||||||
}
|
}
|
||||||
@ -49,7 +48,7 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
if (!CheckValues(out string message))
|
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);
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -58,7 +57,7 @@ namespace BreCalClient
|
|||||||
this.DialogResult = true;
|
this.DialogResult = true;
|
||||||
this.Close();
|
this.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@ -99,16 +98,13 @@ namespace BreCalClient
|
|||||||
|
|
||||||
message = "";
|
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;
|
if (this.datePickerETABerth.Value.IsTooOld() || this.datePickerETABerth_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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.HasValue && this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth.Value > this.datePickerETABerth_End.Value)
|
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;
|
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;
|
if(this.datePickerETDBerth.Value.IsTooOld() || this.datePickerETDBerth_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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.HasValue && this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth.Value > this.datePickerETDBerth_End.Value)
|
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;
|
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;
|
message = BreCalClient.Resources.Resources.textLockTimeInThePast;
|
||||||
return false;
|
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;
|
message = BreCalClient.Resources.Resources.textZoneEntryInThePast;
|
||||||
return false;
|
return false;
|
||||||
@ -154,8 +147,7 @@ namespace BreCalClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) ||
|
if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) || (this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
|
||||||
(this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||||
return false;
|
return false;
|
||||||
@ -218,13 +210,13 @@ namespace BreCalClient
|
|||||||
{
|
{
|
||||||
this.labelETA.Content = string.Format("ETA {0}", BreCalLists.TimeRefs[displayIndex]);
|
this.labelETA.Content = string.Format("ETA {0}", BreCalLists.TimeRefs[displayIndex]);
|
||||||
this.labelETD.Content = string.Format("ETD {0}", BreCalLists.TimeRefs[displayIndex]);
|
this.labelETD.Content = string.Format("ETD {0}", BreCalLists.TimeRefs[displayIndex]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.labelETA.Content = BreCalClient.Resources.Resources.textETABerth;
|
this.labelETA.Content = BreCalClient.Resources.Resources.textETABerth;
|
||||||
this.labelETD.Content = BreCalClient.Resources.Resources.textETDBerth;
|
this.labelETD.Content = BreCalClient.Resources.Resources.textETDBerth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.SetLockButton(this.Times.EtaBerthFixed ?? false);
|
this.SetLockButton(this.Times.EtaBerthFixed ?? false);
|
||||||
}
|
}
|
||||||
@ -290,11 +282,11 @@ namespace BreCalClient
|
|||||||
case Extensions.ParticipantType.PORT_ADMINISTRATION:
|
case Extensions.ParticipantType.PORT_ADMINISTRATION:
|
||||||
this.datePickerLockTime.IsEnabled = true;
|
this.datePickerLockTime.IsEnabled = true;
|
||||||
break;
|
break;
|
||||||
case Extensions.ParticipantType.TUG:
|
case Extensions.ParticipantType.TUG:
|
||||||
case Extensions.ParticipantType.PILOT:
|
case Extensions.ParticipantType.PILOT:
|
||||||
this.datePickerZoneEntry.IsEnabled = (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival);
|
this.datePickerZoneEntry.IsEnabled = (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetLockButton(bool newValue)
|
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.imageFixedOrder.Source = new BitmapImage(new Uri(@"pack://application:,,,/Resources/lock_open.png", UriKind.RelativeOrAbsolute));
|
||||||
this.buttonFixedOrder.ToolTip = BreCalClient.Resources.Resources.textTooltipSetFixedOrder;
|
this.buttonFixedOrder.ToolTip = BreCalClient.Resources.Resources.textTooltipSetFixedOrder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -335,17 +327,17 @@ namespace BreCalClient
|
|||||||
private void contextMenuItemClearZoneEntry_Click(object sender, RoutedEventArgs e)
|
private void contextMenuItemClearZoneEntry_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.datePickerZoneEntry.Value = null;
|
this.datePickerZoneEntry.Value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contextMenuItemClearATA_Click(object sender, RoutedEventArgs e)
|
private void contextMenuItemClearATA_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.datePickerATA.Value = null;
|
this.datePickerATA.Value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contextMenuItemClearATD_Click(object sender, RoutedEventArgs e)
|
private void contextMenuItemClearATD_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
this.datePickerATD.Value = null;
|
this.datePickerATD.Value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contextMenuItemClearETA_End_Click(object sender, RoutedEventArgs e)
|
private void contextMenuItemClearETA_End_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@ -358,6 +350,6 @@ namespace BreCalClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,17 +108,14 @@ namespace BreCalClient
|
|||||||
|
|
||||||
message = "";
|
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;
|
if(this.datePickerOperationStart.Value.IsTooOld() || this.datePickerOperationStart_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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.HasValue && this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart.Value > this.datePickerOperationStart_End.Value)
|
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;
|
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;
|
if(this.datePickerOperationEnd.Value.IsTooOld() || this.datePickerOperationEnd_End.Value.IsTooOld())
|
||||||
return false;
|
{
|
||||||
}
|
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.HasValue && this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd.Value > this.datePickerOperationEnd_End.Value)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) ||
|
if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) || (this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
|
||||||
(this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
|
|
||||||
{
|
{
|
||||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -69,6 +69,14 @@ namespace BreCalClient
|
|||||||
return datetime > DateTime.Now.AddYears(1);
|
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)
|
public static bool IsTypeFlagSet(this Participant participant, ParticipantType flag)
|
||||||
{
|
{
|
||||||
return (participant.Type & (uint)flag) != 0;
|
return (participant.Type & (uint)flag) != 0;
|
||||||
|
|||||||
@ -28,7 +28,7 @@ def validation_error_default_asserts(response):
|
|||||||
def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict):
|
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"""
|
"""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)
|
# 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 #####
|
##### Section 1: check user_data #####
|
||||||
# check, whether the user belongs to a participant, which is of type ParticipantType.BSMD
|
# 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)
|
is_bsmd = check_if_user_is_bsmd_type(user_data)
|
||||||
if not is_bsmd:
|
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}"})
|
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 #####
|
##### Section 2: check loadedModel #####
|
||||||
valid_ship_id = check_if_ship_id_is_valid(ship_id=loadedModel.get("ship_id", None))
|
valid_ship_id = check_if_ship_id_is_valid(ship_id=loadedModel.get("ship_id", None))
|
||||||
if not valid_ship_id:
|
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)}"})
|
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))
|
valid_arrival_berth_id = check_if_berth_id_is_valid(berth_id=loadedModel.get("arrival_berth_id", None))
|
||||||
if not valid_arrival_berth_id:
|
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)}"})
|
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))
|
valid_departure_berth_id = check_if_berth_id_is_valid(berth_id=loadedModel.get("departure_berth_id", None))
|
||||||
if not valid_departure_berth_id:
|
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)}"})
|
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",[]))
|
valid_participant_ids = check_if_participant_ids_are_valid(participants=loadedModel.get("participants",[]))
|
||||||
if not valid_participant_ids:
|
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 #####
|
##### 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)
|
value = content.get(forbidden_key, None)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
raise ValidationError({"forbidden_key":f"'{forbidden_key}' may not be set on POST. Found: {value}"})
|
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",""))
|
voyage_str_is_invalid = check_if_string_has_special_characters(text=content.get("voyage",""))
|
||||||
if voyage_str_is_invalid:
|
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 #####
|
##### Section 4: check loadedModel & content #####
|
||||||
# #TODO_refactor: these methods should be placed in separate locations
|
# #TODO_refactor: these methods should be placed in separate locations
|
||||||
|
|
||||||
# existance checks in content
|
# existance checks in content
|
||||||
# datetime checks in loadedModel (datetime.datetime objects). Dates should be in the future.
|
# datetime checks in loadedModel (datetime.datetime objects). Dates should be in the future.
|
||||||
time_now = datetime.datetime.now()
|
time_now = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||||
type_ = loadedModel.get("type", int(ShipcallType.undefined))
|
type_ = loadedModel.get("type", int(ShipcallType.undefined))
|
||||||
if int(type_)==int(ShipcallType.undefined):
|
if int(type_)==int(ShipcallType.undefined):
|
||||||
raise ValidationError({"type":f"providing 'type' is mandatory. Missing key!"})
|
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:
|
if content.get("arrival_berth_id", None) is None:
|
||||||
raise ValidationError({"arrival_berth_id":f"providing 'arrival_berth_id' is mandatory. Missing key!"})
|
raise ValidationError({"arrival_berth_id":f"providing 'arrival_berth_id' is mandatory. Missing key!"})
|
||||||
if not eta >= time_now:
|
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):
|
elif int(type_)==int(ShipcallType.departure):
|
||||||
etd = loadedModel.get("etd")
|
etd = loadedModel.get("etd")
|
||||||
if (content.get("etd", None) is None):
|
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:
|
if content.get("departure_berth_id", None) is None:
|
||||||
raise ValidationError({"departure_berth_id":f"providing 'departure_berth_id' is mandatory. Missing key!"})
|
raise ValidationError({"departure_berth_id":f"providing 'departure_berth_id' is mandatory. Missing key!"})
|
||||||
if not etd >= time_now:
|
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):
|
elif int(type_)==int(ShipcallType.shifting):
|
||||||
eta = loadedModel.get("eta")
|
eta = loadedModel.get("eta")
|
||||||
etd = loadedModel.get("etd")
|
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):
|
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!"})
|
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):
|
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_from = loadedModel.get("tidal_window_from", None)
|
||||||
tidal_window_to = loadedModel.get("tidal_window_to", None)
|
tidal_window_to = loadedModel.get("tidal_window_to", None)
|
||||||
if tidal_window_to is not None:
|
if tidal_window_to is not None:
|
||||||
if not tidal_window_to >= time_now:
|
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 tidal_window_from is not None:
|
||||||
if not tidal_window_from >= time_now:
|
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: assert tidal_window_from > tidal_window_to
|
||||||
|
|
||||||
# #TODO: len of participants > 0, if agency
|
# #TODO: len of participants > 0, if agency
|
||||||
# * assigned participant for agency
|
# * assigned participant for agency
|
||||||
return
|
return
|
||||||
@ -126,21 +126,21 @@ class InputValidation():
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.build_supported_models_dictionary()
|
self.build_supported_models_dictionary()
|
||||||
return
|
return
|
||||||
|
|
||||||
def build_supported_models_dictionary(self):
|
def build_supported_models_dictionary(self):
|
||||||
self.supported_models = {
|
self.supported_models = {
|
||||||
Ship:ShipValidation(),
|
Ship:ShipValidation(),
|
||||||
Shipcall:ShipcallValidation(),
|
Shipcall:ShipcallValidation(),
|
||||||
Berth:BerthValidation(),
|
Berth:BerthValidation(),
|
||||||
User:UserValidation(),
|
User:UserValidation(),
|
||||||
Participant:ParticipantValidation(),
|
Participant:ParticipantValidation(),
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
||||||
def assert_if_not_supported(self, dataclass_object):
|
def assert_if_not_supported(self, dataclass_object):
|
||||||
assert type(dataclass_object) in self.supported_models, f"unsupported model. Found: {type(dataclass_object)}"
|
assert type(dataclass_object) in self.supported_models, f"unsupported model. Found: {type(dataclass_object)}"
|
||||||
return
|
return
|
||||||
|
|
||||||
def verify(self, dataclass_object):
|
def verify(self, dataclass_object):
|
||||||
self.assert_if_not_supported(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"""
|
"""parent class of dataclas validators, which determines the outline of every object"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
def check(self, dataclass_object) -> (list, bool):
|
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
|
and a boolean, which determines, whether the check is passed successfully
|
||||||
"""
|
"""
|
||||||
all_rules = self.apply_all_rules(dataclass_object)
|
all_rules = self.apply_all_rules(dataclass_object)
|
||||||
violations = self.filter_violations(all_rules)
|
violations = self.filter_violations(all_rules)
|
||||||
input_validation_state = self.evaluate(violations)
|
input_validation_state = self.evaluate(violations)
|
||||||
return (violations, input_validation_state)
|
return (violations, input_validation_state)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def apply_all_rules(self, dataclass_object) -> list:
|
def apply_all_rules(self, dataclass_object) -> list:
|
||||||
"""
|
"""
|
||||||
@ -176,13 +176,13 @@ class DataclassValidation(ABC):
|
|||||||
"""
|
"""
|
||||||
all_rules = [(True, 'blank_validation_rule')]
|
all_rules = [(True, 'blank_validation_rule')]
|
||||||
return all_rules
|
return all_rules
|
||||||
|
|
||||||
def filter_violations(self, 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). """
|
"""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
|
# if output is False, a violation is observed
|
||||||
violations = [result[1] for result in all_rules if not result[0]]
|
violations = [result[1] for result in all_rules if not result[0]]
|
||||||
return violations
|
return violations
|
||||||
|
|
||||||
def evaluate(self, violations) -> bool:
|
def evaluate(self, violations) -> bool:
|
||||||
input_validation_state = len(violations)==0
|
input_validation_state = len(violations)==0
|
||||||
return input_validation_state
|
return input_validation_state
|
||||||
@ -194,7 +194,7 @@ class ShipcallValidation(DataclassValidation):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
return
|
return
|
||||||
|
|
||||||
def apply_all_rules(self, dataclass_object) -> list:
|
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)"""
|
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
|
||||||
raise NotImplementedError()
|
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
|
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):
|
class ShipValidation(DataclassValidation):
|
||||||
"""an object that validates a Ship dataclass object"""
|
"""an object that validates a Ship dataclass object"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
return
|
return
|
||||||
|
|
||||||
def apply_all_rules(self, dataclass_object) -> list:
|
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)"""
|
"""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
|
#TODO_ship_max_draft
|
||||||
with pytest.raises(AttributeError, match="'Ship' object has no attribute '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)
|
check_rule(dataclass_object)
|
||||||
|
|
||||||
for check_rule in [
|
for check_rule in [
|
||||||
ship_bollard_pull_is_defined_or_is_not_tug,
|
ship_bollard_pull_is_defined_or_is_not_tug,
|
||||||
ship_bollard_pull_is_none_or_in_range,
|
ship_bollard_pull_is_none_or_in_range,
|
||||||
ship_callsign_len_is_seven_at_maximum,
|
ship_callsign_len_is_seven_at_maximum,
|
||||||
ship_eni_len_is_eight,
|
ship_eni_len_is_eight,
|
||||||
ship_imo_len_is_seven,
|
ship_imo_len_is_seven,
|
||||||
ship_length_in_range,
|
ship_length_in_range,
|
||||||
ship_participant_id_is_defined_or_is_not_tug,
|
ship_participant_id_is_defined_or_is_not_tug,
|
||||||
ship_participant_id_is_none_or_int,
|
ship_participant_id_is_none_or_int,
|
||||||
ship_width_in_range
|
ship_width_in_range
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@ -243,7 +243,7 @@ class BerthValidation(DataclassValidation):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
return
|
return
|
||||||
|
|
||||||
def apply_all_rules(self, dataclass_object) -> list:
|
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)"""
|
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -254,7 +254,7 @@ class UserValidation(DataclassValidation):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
return
|
return
|
||||||
|
|
||||||
def apply_all_rules(self, dataclass_object) -> list:
|
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)"""
|
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -266,7 +266,7 @@ class ParticipantValidation(DataclassValidation):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
return
|
return
|
||||||
|
|
||||||
def apply_all_rules(self, dataclass_object) -> list:
|
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)"""
|
"""apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
|
||||||
|
|
||||||
|
|||||||
@ -124,11 +124,14 @@ class InputValidationShipcall():
|
|||||||
if check_if_int_is_valid_flag(flags_value, enum_object=ParticipantFlag):
|
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."})
|
raise ValidationError({"flags":f"incorrect value provided for 'flags'. Must be a valid combination of the flags."})
|
||||||
|
|
||||||
|
existing_shipcall = None
|
||||||
if is_put_data:
|
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.
|
# 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_shipcall_type_is_unchanged(loadedModel, existing_shipcall)
|
||||||
|
|
||||||
InputValidationShipcall.check_times_are_in_future(loadedModel, content)
|
InputValidationShipcall.check_times_are_in_future(loadedModel, content, existing_shipcall)
|
||||||
|
|
||||||
# some arguments must not be provided
|
# some arguments must not be provided
|
||||||
InputValidationShipcall.check_forbidden_arguments(content, forbidden_keys=forbidden_keys)
|
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."})
|
raise ValidationError({"participants":f"every participant id and type should be listed only once. Found multiple entries for one of the participants."})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_shipcall_type_is_unchanged(loadedModel:dict):
|
def check_shipcall_type_is_unchanged(loadedModel:dict, existing_shipcall:object):
|
||||||
# the type of a shipcall may only be set on POST requests. Afterwards, shipcall types may not be changed.
|
if int(loadedModel["type"]) != int(existing_shipcall.type):
|
||||||
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):
|
|
||||||
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
|
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
|
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
|
@staticmethod
|
||||||
def check_forbidden_arguments(content:dict, forbidden_keys=["evaluation", "evaluation_message"]):
|
def check_forbidden_arguments(content:dict, forbidden_keys=["evaluation", "evaluation_message"]):
|
||||||
"""
|
"""
|
||||||
@ -324,13 +329,13 @@ class InputValidationShipcall():
|
|||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@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
|
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
|
# obtain the current datetime to check, whether the provided values are after ref time
|
||||||
time_now = datetime.datetime.now()
|
time_ref = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||||
|
|
||||||
type_ = loadedModel.get("type", ShipcallType.undefined.name)
|
type_ = loadedModel.get("type", ShipcallType.undefined.name)
|
||||||
if isinstance(type_, str): # convert the name string to a ShipcallType data model
|
if isinstance(type_, str): # convert the name string to a ShipcallType data model
|
||||||
@ -346,16 +351,29 @@ class InputValidationShipcall():
|
|||||||
etd = loadedModel.get("etd")
|
etd = loadedModel.get("etd")
|
||||||
tidal_window_from = loadedModel.get("tidal_window_from", None)
|
tidal_window_from = loadedModel.get("tidal_window_from", None)
|
||||||
tidal_window_to = loadedModel.get("tidal_window_to", 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
|
if existing_shipcall is not None:
|
||||||
InputValidationShipcall.check_times_in_future_based_on_type(type_, time_now, eta, etd)
|
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
|
return
|
||||||
|
|
||||||
@staticmethod
|
@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.
|
checks, whether the ETA & ETD times are in the future.
|
||||||
based on the type, this function checks:
|
based on the type, this function checks:
|
||||||
@ -365,8 +383,8 @@ class InputValidationShipcall():
|
|||||||
"""
|
"""
|
||||||
if (eta is None) and (etd is None):
|
if (eta is None) and (etd is None):
|
||||||
return
|
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:
|
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."})
|
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
|
if eta is None: # null values -> no violation
|
||||||
return
|
return
|
||||||
|
|
||||||
if not eta > time_now:
|
if not eta > time_ref:
|
||||||
raise ValidationError({"eta":f"'eta' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}."})
|
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:
|
if etd is not None:
|
||||||
raise ValidationError({"etd":f"'etd' should not be set when the shipcall type is 'arrival'."})
|
raise ValidationError({"etd":f"'etd' should not be set when the shipcall type is 'arrival'."})
|
||||||
if eta > time_in_a_year:
|
if eta > time_in_a_year:
|
||||||
@ -392,8 +410,9 @@ class InputValidationShipcall():
|
|||||||
if etd is None: # null values -> no violation
|
if etd is None: # null values -> no violation
|
||||||
return
|
return
|
||||||
|
|
||||||
if not etd > time_now:
|
if not etd > time_ref:
|
||||||
raise ValidationError({"etd":f"'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETD: {etd}."})
|
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:
|
if eta is not None:
|
||||||
raise ValidationError({"eta":f"'eta' should not be set when the shipcall type is 'departure'."})
|
raise ValidationError({"eta":f"'eta' should not be set when the shipcall type is 'departure'."})
|
||||||
if etd > time_in_a_year:
|
if etd > time_in_a_year:
|
||||||
@ -408,8 +427,8 @@ class InputValidationShipcall():
|
|||||||
# rules, a user is only allowed to provide *both* values.
|
# 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."})
|
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):
|
if (not eta > time_ref) or (not etd > time_ref):
|
||||||
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}"})
|
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):
|
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}"})
|
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}."})
|
raise ValidationError({"eta":f"'eta' is more than a year in the future. ETA: {eta}."})
|
||||||
if etd > time_in_a_year:
|
if etd > time_in_a_year:
|
||||||
raise ValidationError({"etd":f"'etd' is more than a year in the future. ETD: {etd}."})
|
raise ValidationError({"etd":f"'etd' is more than a year in the future. ETD: {etd}."})
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_tidal_window_in_future(type_, time_now, tidal_window_from, tidal_window_to):
|
def check_tidal_window_in_future(type_, time_ref, tidal_window_from, tidal_window_to):
|
||||||
|
|
||||||
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 tidal_window_to is not None:
|
if tidal_window_to is not None:
|
||||||
if not tidal_window_to >= time_now:
|
if not tidal_window_to >= time_ref:
|
||||||
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_to > time_in_a_year:
|
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}."})
|
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 tidal_window_from is not None:
|
||||||
if not tidal_window_from >= time_now:
|
if not tidal_window_from >= time_ref:
|
||||||
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."})
|
||||||
if tidal_window_from > time_in_a_year:
|
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}."})
|
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 is not None) and (tidal_window_from is not None):
|
||||||
if tidal_window_to < tidal_window_from:
|
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}."})
|
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):
|
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."})
|
raise ValidationError({"tidal_window_to_or_tidal_window_from":f"'tidal_window_to' and 'tidal_window_from' must both be provided."})
|
||||||
|
|
||||||
|
|||||||
@ -414,6 +414,8 @@ class InputValidationTimes():
|
|||||||
# commonly used in the PUT-request
|
# commonly used in the PUT-request
|
||||||
if loadedModel is not None:
|
if loadedModel is not None:
|
||||||
(shipcall_id, times_assigned_participant) = InputValidationTimes.prepare_authority_check_for_put_request(loadedModel)
|
(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
|
# commonly used in the DELETE-request
|
||||||
if times_id is not None:
|
if times_id is not None:
|
||||||
|
|||||||
@ -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"):
|
with pytest.raises(ValidationError, match="Longer than maximum length 16"):
|
||||||
assert response.status_code==400
|
assert response.status_code==400
|
||||||
raise ValidationError(response.json())
|
raise ValidationError(response.json())
|
||||||
|
|
||||||
# Fail: special characters
|
# Fail: special characters
|
||||||
post_data = original_post_data.copy()
|
post_data = original_post_data.copy()
|
||||||
post_data["voyage"] = '👽'
|
post_data["voyage"] = '👽'
|
||||||
@ -226,17 +226,17 @@ def test_shipcall_post_request_fails_when_type_arrival_and_not_in_future(get_stu
|
|||||||
# accept
|
# accept
|
||||||
post_data = original_post_data.copy()
|
post_data = original_post_data.copy()
|
||||||
post_data["type"] = ShipcallType.arrival.name
|
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)
|
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
# error
|
# error
|
||||||
post_data = original_post_data.copy()
|
post_data = original_post_data.copy()
|
||||||
post_data["type"] = ShipcallType.arrival.name
|
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)
|
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
|
assert response.status_code==400
|
||||||
raise ValidationError(response.json())
|
raise ValidationError(response.json())
|
||||||
return
|
return
|
||||||
@ -256,10 +256,10 @@ def test_shipcall_post_request_fails_when_type_departure_and_not_in_future(get_s
|
|||||||
# error
|
# error
|
||||||
post_data = original_post_data.copy()
|
post_data = original_post_data.copy()
|
||||||
post_data["type"] = ShipcallType.departure.name
|
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)
|
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
|
assert response.status_code==400
|
||||||
raise ValidationError(response.json())
|
raise ValidationError(response.json())
|
||||||
return
|
return
|
||||||
@ -280,11 +280,11 @@ def test_shipcall_post_request_fails_when_type_shifting_and_not_in_future(get_st
|
|||||||
# error
|
# error
|
||||||
post_data = original_post_data.copy()
|
post_data = original_post_data.copy()
|
||||||
post_data["type"] = ShipcallType.shifting.name
|
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()
|
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)
|
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
|
assert response.status_code==400
|
||||||
raise ValidationError(response.json())
|
raise ValidationError(response.json())
|
||||||
return
|
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}]
|
{"id":99115, 'participant_id': 5, 'type': 8}]
|
||||||
spm_shipcall_data = [
|
spm_shipcall_data = [
|
||||||
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
||||||
for spm in
|
for spm in
|
||||||
spm_shipcall_data
|
spm_shipcall_data
|
||||||
]
|
]
|
||||||
spm_shipcall_data = [ShipcallParticipantMap(**spm) 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}
|
user_data = {'id':6, 'participant_id':1}
|
||||||
loadedModel = post_data
|
loadedModel = post_data
|
||||||
content = post_data
|
content = post_data
|
||||||
|
|
||||||
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
|
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
|
||||||
modified = datetime.datetime.now()+datetime.timedelta(minutes=2)
|
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}]
|
{"id":99115, 'participant_id': 5, 'type': 8}]
|
||||||
spm_shipcall_data = [
|
spm_shipcall_data = [
|
||||||
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
||||||
for spm in
|
for spm in
|
||||||
spm_shipcall_data
|
spm_shipcall_data
|
||||||
]
|
]
|
||||||
spm_shipcall_data = [ShipcallParticipantMap(**spm) 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.
|
user_data = {'id':6, 'participant_id':2} # participant_id 2 is not BSMD and is not authorized.
|
||||||
loadedModel = post_data
|
loadedModel = post_data
|
||||||
content = post_data
|
content = post_data
|
||||||
|
|
||||||
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
|
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
|
||||||
modified = datetime.datetime.now()+datetime.timedelta(minutes=2)
|
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}]
|
{"id":99115, 'participant_id': 5, 'type': 4}]
|
||||||
spm_shipcall_data = [
|
spm_shipcall_data = [
|
||||||
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
||||||
for spm in
|
for spm in
|
||||||
spm_shipcall_data
|
spm_shipcall_data
|
||||||
]
|
]
|
||||||
spm_shipcall_data = [ShipcallParticipantMap(**spm) 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
|
# no agency assigned
|
||||||
ivs = InputValidationShipcall()
|
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.")):
|
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)
|
ivs.check_user_is_authorized_for_put_request(user_data, loadedModel, content, spm_shipcall_data)
|
||||||
return
|
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}]
|
{"id":99115, 'participant_id': 5, 'type': 4}]
|
||||||
spm_shipcall_data = [
|
spm_shipcall_data = [
|
||||||
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
||||||
for spm in
|
for spm in
|
||||||
spm_shipcall_data
|
spm_shipcall_data
|
||||||
]
|
]
|
||||||
spm_shipcall_data = [ShipcallParticipantMap(**spm) 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)
|
created = datetime.datetime.now()+datetime.timedelta(minutes=1)
|
||||||
modified = datetime.datetime.now()+datetime.timedelta(minutes=2)
|
modified = datetime.datetime.now()+datetime.timedelta(minutes=2)
|
||||||
|
|
||||||
spm_shipcall_data = [
|
spm_shipcall_data = [
|
||||||
{"id":99113, 'participant_id': 3, 'type': 1},
|
{"id":99113, 'participant_id': 3, 'type': 1},
|
||||||
{"id":99114, 'participant_id': 4, 'type': 2},
|
{"id":99114, 'participant_id': 4, 'type': 2},
|
||||||
{"id":99115, 'participant_id': 5, 'type': 4}]
|
{"id":99115, 'participant_id': 5, 'type': 4}]
|
||||||
spm_shipcall_data = [
|
spm_shipcall_data = [
|
||||||
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
{**{"created":created, "modified":modified, "shipcall_id":shipcall_id}, **spm}
|
||||||
for spm in
|
for spm in
|
||||||
spm_shipcall_data
|
spm_shipcall_data
|
||||||
]
|
]
|
||||||
spm_shipcall_data = [ShipcallParticipantMap(**spm) 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()
|
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.")):
|
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.""
|
# 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)
|
InputValidationShipcall.evaluate_put_data(user_data, loadedModel, content)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -860,10 +860,10 @@ def test_shipcall_put_request_fails_input_validation_shipcall_when_shipcall_is_c
|
|||||||
return
|
return
|
||||||
|
|
||||||
def test_post_data_with_valid_data(get_stub_token):
|
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
|
# 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"]
|
url, token = get_stub_token["url"], get_stub_token["token"]
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user