Compare commits
19 Commits
develop
...
feature/te
| Author | SHA1 | Date | |
|---|---|---|---|
| 529872b590 | |||
| f1e1355986 | |||
| e911da20ef | |||
| 2ee9af4b9d | |||
| 5e2cb3f745 | |||
| 704c58222c | |||
| 401e0d4ae8 | |||
|
|
c0902c65ee | ||
| 8fe2a9ebca | |||
| d62250fb4f | |||
| 28404fb8b6 | |||
| 40e1c91755 | |||
| 7921a138d4 | |||
| 0c8a5cfc2c | |||
| 27179da2a2 | |||
| df050cb83b | |||
|
|
5e50e09966 | ||
| 0bd526e08e | |||
|
|
8df9034574 |
@ -8,8 +8,8 @@
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<StartupObject>BreCalClient.App</StartupObject>
|
||||
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
|
||||
<AssemblyVersion>1.5.0.4</AssemblyVersion>
|
||||
<FileVersion>1.5.0.4</FileVersion>
|
||||
<AssemblyVersion>1.5.0.7</AssemblyVersion>
|
||||
<FileVersion>1.5.0.7</FileVersion>
|
||||
<Title>Bremen calling client</Title>
|
||||
<Description>A Windows WPF client for the Bremen calling API.</Description>
|
||||
<ApplicationIcon>containership.ico</ApplicationIcon>
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
<Label x:Name="labelBSMDGranted" Grid.Row="7" Grid.Column="3" Grid.ColumnSpan="1" Content="{x:Static p:Resources.textBSMDGranted}" Visibility="Hidden" FontWeight="DemiBold" />
|
||||
|
||||
<Label x:Name="labelShiftingCount" Grid.Row="6" Grid.Column="2" HorizontalAlignment="Right" Content="{x:Static p:Resources.textShiftingSequence}" />
|
||||
<xctk:IntegerUpDown x:Name="integerUpDownShiftingCount" Grid.Row="6" Grid.Column="3" Margin="2" Minimum="0" Maximum="255" />
|
||||
<xctk:IntegerUpDown x:Name="integerUpDownShiftingCount" Grid.Row="6" Grid.Column="3" Margin="2" Minimum="0" Maximum="127" />
|
||||
|
||||
<StackPanel Grid.Row="8" Grid.Column="3" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Width= "80" Margin="2" Content="{x:Static p:Resources.textOK}" x:Name="buttonOK" Click="buttonOK_Click" IsEnabled="False" />
|
||||
|
||||
@ -73,7 +73,7 @@ namespace BreCalClient
|
||||
{
|
||||
if (!CheckValues(out string message))
|
||||
{
|
||||
MessageBox.Show(message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -145,6 +145,13 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ namespace BreCalClient
|
||||
{
|
||||
if (!CheckValues(out string message))
|
||||
{
|
||||
System.Windows.MessageBox.Show(message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -155,6 +155,13 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ namespace BreCalClient
|
||||
{
|
||||
if (!CheckValues(out string message))
|
||||
{
|
||||
System.Windows.MessageBox.Show(message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -164,6 +164,14 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) ||
|
||||
(this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) ||
|
||||
(this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
||||
{
|
||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,8 @@ namespace BreCalClient
|
||||
{
|
||||
if (!CheckValues(out string message))
|
||||
{
|
||||
System.Windows.MessageBox.Show(message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning,
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -116,6 +117,24 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.datePickerETDBerth.Value.HasValue && (this.datePickerETDBerth.Value.Value < DateTime.Now) && (this.datePickerETABerth_End.Value == null))
|
||||
{
|
||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth_End.Value < DateTime.Now)
|
||||
{
|
||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.datePickerETDBerth.Value.HasValue && this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth.Value > this.datePickerETDBerth_End.Value)
|
||||
{
|
||||
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.datePickerLockTime.Value.HasValue && (this.datePickerLockTime.Value.Value < DateTime.Now))
|
||||
{
|
||||
message = BreCalClient.Resources.Resources.textLockTimeInThePast;
|
||||
@ -135,6 +154,13 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@ namespace BreCalClient
|
||||
{
|
||||
if (!CheckValues(out string message))
|
||||
{
|
||||
System.Windows.MessageBox.Show(message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -150,6 +150,13 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.5.0.4</ApplicationVersion>
|
||||
<ApplicationVersion>1.5.0.7</ApplicationVersion>
|
||||
<BootstrapperEnabled>True</BootstrapperEnabled>
|
||||
<Configuration>Debug</Configuration>
|
||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||
|
||||
27
src/BreCalClient/Resources/Resources.Designer.cs
generated
27
src/BreCalClient/Resources/Resources.Designer.cs
generated
@ -119,6 +119,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
public static string arrow_right_blue {
|
||||
get {
|
||||
return ResourceManager.GetString("arrow_right_blue", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
@ -139,6 +148,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
public static string arrow_up_green {
|
||||
get {
|
||||
return ResourceManager.GetString("arrow_up_green", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
@ -1199,6 +1217,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to If an end time is set, a start time is also required.
|
||||
/// </summary>
|
||||
public static string textStartTimeMissing {
|
||||
get {
|
||||
return ResourceManager.GetString("textStartTimeMissing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Terminal.
|
||||
/// </summary>
|
||||
|
||||
@ -117,16 +117,13 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Arrival" xml:space="preserve">
|
||||
<value>Einkommend</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="arrow_down_red" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>arrow_down_red.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="arrow_right_blue" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>arrow_right_blue.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="arrow_up_green" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>arrow_up_green.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="clipboard" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>clipboard.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
@ -136,15 +133,24 @@
|
||||
<data name="containership" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>containership.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Departure" xml:space="preserve">
|
||||
<value>Ausgehend</value>
|
||||
</data>
|
||||
<data name="emergency_stop_button" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>emergency_stop_button.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="logo_bremen_calling" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>logo_bremen_calling.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Shifting" xml:space="preserve">
|
||||
<value>Verholung</value>
|
||||
</data>
|
||||
<data name="ship2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>ship2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="textAdd" xml:space="preserve">
|
||||
<value>Hinzufügen</value>
|
||||
</data>
|
||||
<data name="textAgencies" xml:space="preserve">
|
||||
<value>Agenturen</value>
|
||||
</data>
|
||||
@ -160,9 +166,18 @@
|
||||
<data name="textBerth" xml:space="preserve">
|
||||
<value>Liegeplatz</value>
|
||||
</data>
|
||||
<data name="textBerthRemarks" xml:space="preserve">
|
||||
<value>Liegeplatz Informationen</value>
|
||||
</data>
|
||||
<data name="textBerths" xml:space="preserve">
|
||||
<value>Liegeplätze</value>
|
||||
</data>
|
||||
<data name="textBothTideTimesNecessary" xml:space="preserve">
|
||||
<value>Beide Tidenzeiten sollten angegeben werden (von - bis)</value>
|
||||
</data>
|
||||
<data name="textBSMDGranted" xml:space="preserve">
|
||||
<value>Freigabe zur Bearb. f. BSMD erteilt</value>
|
||||
</data>
|
||||
<data name="textBunkering" xml:space="preserve">
|
||||
<value>Bunkeraufnahme</value>
|
||||
</data>
|
||||
@ -181,59 +196,122 @@
|
||||
<data name="textChange" xml:space="preserve">
|
||||
<value>Ändern</value>
|
||||
</data>
|
||||
<data name="textChangeContactInfo" xml:space="preserve">
|
||||
<value>Kontaktdaten bearbeiten</value>
|
||||
</data>
|
||||
<data name="textChangeHistory" xml:space="preserve">
|
||||
<value>Verlauf</value>
|
||||
</data>
|
||||
<data name="textChangePassword" xml:space="preserve">
|
||||
<value>Passwort ändern</value>
|
||||
</data>
|
||||
<data name="textClearAll" xml:space="preserve">
|
||||
<value>Alle Eintragungen zurücksetzen?</value>
|
||||
</data>
|
||||
<data name="textClearAssignment" xml:space="preserve">
|
||||
<value>Zuordnung entfernen</value>
|
||||
</data>
|
||||
<data name="textClearFilters" xml:space="preserve">
|
||||
<value>Filter löschen</value>
|
||||
</data>
|
||||
<data name="textClearValue" xml:space="preserve">
|
||||
<value>Eingabe löschen</value>
|
||||
</data>
|
||||
<data name="textClose" xml:space="preserve">
|
||||
<value>Schliessen</value>
|
||||
</data>
|
||||
<data name="textConfirmation" xml:space="preserve">
|
||||
<value>Bestätigung</value>
|
||||
</data>
|
||||
<data name="textDelete" xml:space="preserve">
|
||||
<value>Löschen</value>
|
||||
</data>
|
||||
<data name="textDeleted" xml:space="preserve">
|
||||
<value>Gelöscht</value>
|
||||
</data>
|
||||
<data name="textDepartureTerminal" xml:space="preserve">
|
||||
<value>Terminal Abfahrt</value>
|
||||
</data>
|
||||
<data name="textDraft" xml:space="preserve">
|
||||
<value>Tiefgang (m)</value>
|
||||
</data>
|
||||
<data name="textEdit" xml:space="preserve">
|
||||
<value>Bearbeiten</value>
|
||||
</data>
|
||||
<data name="textEditShip" xml:space="preserve">
|
||||
<value>Schiff bearbeiten</value>
|
||||
</data>
|
||||
<data name="textEditShipcall" xml:space="preserve">
|
||||
<value>Schiffsanlauf bearbeiten</value>
|
||||
</data>
|
||||
<data name="textEditShips" xml:space="preserve">
|
||||
<value>Schiffe anlegen / bearbeiten</value>
|
||||
</data>
|
||||
<data name="textEditTimes" xml:space="preserve">
|
||||
<value>Zeiten bearbeiten</value>
|
||||
</data>
|
||||
<data name="textETABerth" xml:space="preserve">
|
||||
<value>ETA Liegeplatz</value>
|
||||
<data name="textEmail" xml:space="preserve">
|
||||
<value>E-Mail</value>
|
||||
</data>
|
||||
<data name="textETDBerth" xml:space="preserve">
|
||||
<value>ETD Liegeplatz</value>
|
||||
<data name="textEndValueBeforeStartValue" xml:space="preserve">
|
||||
<value>Endzeit liegt vor Startzeit</value>
|
||||
</data>
|
||||
<data name="textEnterKeyword" xml:space="preserve">
|
||||
<value>Schiff / Bemerkung</value>
|
||||
</data>
|
||||
<data name="textError" xml:space="preserve">
|
||||
<value>Error</value>
|
||||
</data>
|
||||
<data name="textETABerth" xml:space="preserve">
|
||||
<value>ETA Liegeplatz</value>
|
||||
</data>
|
||||
<data name="textETAInThePast" xml:space="preserve">
|
||||
<value>Zeitpunkt ETA liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textETDBerth" xml:space="preserve">
|
||||
<value>ETD Liegeplatz</value>
|
||||
</data>
|
||||
<data name="textETDInThePast" xml:space="preserve">
|
||||
<value>Zeitpunkt ETD liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textExit" xml:space="preserve">
|
||||
<value>Verlassen</value>
|
||||
</data>
|
||||
<data name="textFrom" xml:space="preserve">
|
||||
<value>von</value>
|
||||
</data>
|
||||
<data name="textInterval" xml:space="preserve">
|
||||
<value>Zeitraum</value>
|
||||
</data>
|
||||
<data name="textLengthWidth" xml:space="preserve">
|
||||
<value>L/B (m)</value>
|
||||
</data>
|
||||
<data name="textLogin" xml:space="preserve">
|
||||
<value>Anmelden</value>
|
||||
</data>
|
||||
<data name="textFixed" xml:space="preserve">
|
||||
<value>Fest</value>
|
||||
</data>
|
||||
<data name="textFixedOrder" xml:space="preserve">
|
||||
<value>Als feste Bestellung vermerkt</value>
|
||||
</data>
|
||||
<data name="textFrom" xml:space="preserve">
|
||||
<value>von</value>
|
||||
</data>
|
||||
<data name="textIncoming" xml:space="preserve">
|
||||
<value>Einkommend</value>
|
||||
</data>
|
||||
<data name="textInfoChangePW" xml:space="preserve">
|
||||
<value>App Info anzeigen und Passwort ändern</value>
|
||||
</data>
|
||||
<data name="textInterval" xml:space="preserve">
|
||||
<value>Zeitraum</value>
|
||||
</data>
|
||||
<data name="textLength" xml:space="preserve">
|
||||
<value>Länge</value>
|
||||
</data>
|
||||
<data name="textLengthWidth" xml:space="preserve">
|
||||
<value>L/B (m)</value>
|
||||
</data>
|
||||
<data name="textLockTime" xml:space="preserve">
|
||||
<value>Zeit Schleuse</value>
|
||||
</data>
|
||||
<data name="textOperationsEnd" xml:space="preserve">
|
||||
<value>Operation Ende</value>
|
||||
<data name="textLockTimeInThePast" xml:space="preserve">
|
||||
<value>Schleusenzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textOperationsStart" xml:space="preserve">
|
||||
<value>Operation Start</value>
|
||||
<data name="textLogin" xml:space="preserve">
|
||||
<value>Anmelden</value>
|
||||
</data>
|
||||
<data name="textMineOnly" xml:space="preserve">
|
||||
<value>nur eigene</value>
|
||||
</data>
|
||||
<data name="textMooredLock" xml:space="preserve">
|
||||
<value>auch in Schleuse</value>
|
||||
@ -250,21 +328,45 @@
|
||||
<data name="textNotRotated" xml:space="preserve">
|
||||
<value>Ungedreht</value>
|
||||
</data>
|
||||
<data name="textZoneEntryTime" xml:space="preserve">
|
||||
<value>Reviereintritt</value>
|
||||
</data>
|
||||
<data name="textOK" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="textOldPassword" xml:space="preserve">
|
||||
<value>Altes Passwort</value>
|
||||
</data>
|
||||
<data name="textOperation" xml:space="preserve">
|
||||
<value>Vorgang</value>
|
||||
</data>
|
||||
<data name="textOperationEndInThePast" xml:space="preserve">
|
||||
<value>Operation Endzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textOperationsEnd" xml:space="preserve">
|
||||
<value>Operation Ende</value>
|
||||
</data>
|
||||
<data name="textOperationsStart" xml:space="preserve">
|
||||
<value>Operation Start</value>
|
||||
</data>
|
||||
<data name="textOperationStartInThePast" xml:space="preserve">
|
||||
<value>Operation Startzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textOutgoing" xml:space="preserve">
|
||||
<value>Ausgehend</value>
|
||||
</data>
|
||||
<data name="textParticipant" xml:space="preserve">
|
||||
<value>Teilnehmer</value>
|
||||
</data>
|
||||
<data name="textParticipants" xml:space="preserve">
|
||||
<value>Teilnehmer</value>
|
||||
</data>
|
||||
<data name="textPassword" xml:space="preserve">
|
||||
<value>Passwort</value>
|
||||
</data>
|
||||
<data name="textPasswordChanged" xml:space="preserve">
|
||||
<value>Passwort geändert.</value>
|
||||
</data>
|
||||
<data name="textPhone" xml:space="preserve">
|
||||
<value>Telefon</value>
|
||||
</data>
|
||||
<data name="textPierside" xml:space="preserve">
|
||||
<value>Anlegeseite</value>
|
||||
</data>
|
||||
@ -274,12 +376,24 @@
|
||||
<data name="textPilotRequired" xml:space="preserve">
|
||||
<value>Lotsorder</value>
|
||||
</data>
|
||||
<data name="textPilots" xml:space="preserve">
|
||||
<value>Flusslotsen</value>
|
||||
</data>
|
||||
<data name="textPort" xml:space="preserve">
|
||||
<value>Backbord</value>
|
||||
</data>
|
||||
<data name="textPortAuthority" xml:space="preserve">
|
||||
<value>Hafenamt</value>
|
||||
</data>
|
||||
<data name="textRainSensitiveCargo" xml:space="preserve">
|
||||
<value>Regensensitive Ladung</value>
|
||||
</data>
|
||||
<data name="textRecommendedTugs" xml:space="preserve">
|
||||
<value>Anzahl Schlepper</value>
|
||||
</data>
|
||||
<data name="textRemarks" xml:space="preserve">
|
||||
<value>Info</value>
|
||||
</data>
|
||||
<data name="textRepeatNewPassword" xml:space="preserve">
|
||||
<value>Neues Passwort wiederholen</value>
|
||||
</data>
|
||||
@ -295,27 +409,75 @@
|
||||
<data name="textSearch" xml:space="preserve">
|
||||
<value>Suche</value>
|
||||
</data>
|
||||
<data name="textShifting" xml:space="preserve">
|
||||
<value>Verholung</value>
|
||||
</data>
|
||||
<data name="textShiftingFrom" xml:space="preserve">
|
||||
<value>Verholung von</value>
|
||||
</data>
|
||||
<data name="textShiftingSequence" xml:space="preserve">
|
||||
<value>Verhol. Nr.</value>
|
||||
</data>
|
||||
<data name="textShiftingTo" xml:space="preserve">
|
||||
<value>Verholung nach</value>
|
||||
</data>
|
||||
<data name="textShip" xml:space="preserve">
|
||||
<value>Schiff</value>
|
||||
</data>
|
||||
<data name="textShipLength" xml:space="preserve">
|
||||
<value>Schiffslänge</value>
|
||||
</data>
|
||||
<data name="textShips" xml:space="preserve">
|
||||
<value>Schiffe</value>
|
||||
</data>
|
||||
<data name="textShowCancelledShipcalls" xml:space="preserve">
|
||||
<value>Stornierte anzeigen</value>
|
||||
</data>
|
||||
<data name="textShowHistory" xml:space="preserve">
|
||||
<value>Änderungshistorie der Anläufe anzeigen</value>
|
||||
</data>
|
||||
<data name="textSortOrder" xml:space="preserve">
|
||||
<value>Sortierung</value>
|
||||
</data>
|
||||
<data name="textStarboard" xml:space="preserve">
|
||||
<value>Steuerbord</value>
|
||||
</data>
|
||||
<data name="textTerminal" xml:space="preserve">
|
||||
<value>Terminal</value>
|
||||
</data>
|
||||
<data name="textTidalBothValues" xml:space="preserve">
|
||||
<value>Für das Tidenfenster müssen beide Zeiten angegeben werden</value>
|
||||
</data>
|
||||
<data name="textTidalWindow" xml:space="preserve">
|
||||
<value>Tidenfenster</value>
|
||||
</data>
|
||||
<data name="textTideTimesInThePast" xml:space="preserve">
|
||||
<value>Tidenzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textTimestamp" xml:space="preserve">
|
||||
<value>Zeitpunkt</value>
|
||||
</data>
|
||||
<data name="textTo" xml:space="preserve">
|
||||
<value>bis</value>
|
||||
</data>
|
||||
<data name="textTooFarInTheFuture" xml:space="preserve">
|
||||
<value>Eine Zeiteingabe ist zu weit in der Zukunft</value>
|
||||
</data>
|
||||
<data name="textTooltipSetFixedOrder" xml:space="preserve">
|
||||
<value>Als feste Bestellung vermerken</value>
|
||||
</data>
|
||||
<data name="textTooltipUnSetFixedOrder" xml:space="preserve">
|
||||
<value>Feste Bestellung zurücknehmen</value>
|
||||
</data>
|
||||
<data name="textTriggerManualRefresh" xml:space="preserve">
|
||||
<value>Manuelle Aktualisierung der Anläufe auslösen</value>
|
||||
</data>
|
||||
<data name="textTug" xml:space="preserve">
|
||||
<value>Schlepper</value>
|
||||
</data>
|
||||
<data name="textTugCompany" xml:space="preserve">
|
||||
<value>Schlepper-Reederei</value>
|
||||
</data>
|
||||
<data name="textTugRequired" xml:space="preserve">
|
||||
<value>Schlepperorder</value>
|
||||
</data>
|
||||
@ -328,9 +490,27 @@
|
||||
<data name="textUsername" xml:space="preserve">
|
||||
<value>Benutzername</value>
|
||||
</data>
|
||||
<data name="textUserNamePasswordEmpty" xml:space="preserve">
|
||||
<value>Benutzername / Passwort leer!</value>
|
||||
</data>
|
||||
<data name="textVoyage" xml:space="preserve">
|
||||
<value>Reise</value>
|
||||
</data>
|
||||
<data name="textWarning" xml:space="preserve">
|
||||
<value>Warnung</value>
|
||||
</data>
|
||||
<data name="textWidth" xml:space="preserve">
|
||||
<value>Breite</value>
|
||||
</data>
|
||||
<data name="textWrongCredentials" xml:space="preserve">
|
||||
<value>Benutzername / Passwort falsch</value>
|
||||
</data>
|
||||
<data name="textZoneEntryInThePast" xml:space="preserve">
|
||||
<value>Zeit Reviereintritt liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textZoneEntryTime" xml:space="preserve">
|
||||
<value>Reviereintritt</value>
|
||||
</data>
|
||||
<data name="trafficlight_green" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>trafficlight_green.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
@ -355,196 +535,19 @@
|
||||
<data name="umbrella_open" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>umbrella_open.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="worker2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>worker2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="textClearAssignment" xml:space="preserve">
|
||||
<value>Zuordnung entfernen</value>
|
||||
</data>
|
||||
<data name="textClearValue" xml:space="preserve">
|
||||
<value>Eingabe löschen</value>
|
||||
</data>
|
||||
<data name="textConfirmation" xml:space="preserve">
|
||||
<value>Bestätigung</value>
|
||||
</data>
|
||||
<data name="textPasswordChanged" xml:space="preserve">
|
||||
<value>Passwort geändert.</value>
|
||||
</data>
|
||||
<data name="textClearFilters" xml:space="preserve">
|
||||
<value>Filter löschen</value>
|
||||
</data>
|
||||
<data name="textShowCancelledShipcalls" xml:space="preserve">
|
||||
<value>Stornierte anzeigen</value>
|
||||
</data>
|
||||
<data name="textBerthRemarks" xml:space="preserve">
|
||||
<value>Liegeplatz Informationen</value>
|
||||
</data>
|
||||
<data name="textBSMDGranted" xml:space="preserve">
|
||||
<value>Freigabe zur Bearb. f. BSMD erteilt</value>
|
||||
</data>
|
||||
<data name="textRemarks" xml:space="preserve">
|
||||
<value>Info</value>
|
||||
</data>
|
||||
<data name="textIncoming" xml:space="preserve">
|
||||
<value>Einkommend</value>
|
||||
</data>
|
||||
<data name="textOutgoing" xml:space="preserve">
|
||||
<value>Ausgehend</value>
|
||||
</data>
|
||||
<data name="textShifting" xml:space="preserve">
|
||||
<value>Verholung</value>
|
||||
</data>
|
||||
<data name="textLength" xml:space="preserve">
|
||||
<value>Länge</value>
|
||||
</data>
|
||||
<data name="textShiftingFrom" xml:space="preserve">
|
||||
<value>Verholung von</value>
|
||||
</data>
|
||||
<data name="textShiftingTo" xml:space="preserve">
|
||||
<value>Verholung nach</value>
|
||||
</data>
|
||||
<data name="textWidth" xml:space="preserve">
|
||||
<value>Breite</value>
|
||||
</data>
|
||||
<data name="textChangeContactInfo" xml:space="preserve">
|
||||
<value>Kontaktdaten bearbeiten</value>
|
||||
</data>
|
||||
<data name="textEmail" xml:space="preserve">
|
||||
<value>E-Mail</value>
|
||||
</data>
|
||||
<data name="textPhone" xml:space="preserve">
|
||||
<value>Telefon</value>
|
||||
</data>
|
||||
<data name="textWrongCredentials" xml:space="preserve">
|
||||
<value>Benutzername / Passwort falsch</value>
|
||||
</data>
|
||||
<data name="textUserNamePasswordEmpty" xml:space="preserve">
|
||||
<value>Benutzername / Passwort leer!</value>
|
||||
</data>
|
||||
<data name="textPort" xml:space="preserve">
|
||||
<value>Backbord</value>
|
||||
</data>
|
||||
<data name="textStarboard" xml:space="preserve">
|
||||
<value>Steuerbord</value>
|
||||
</data>
|
||||
<data name="textAdd" xml:space="preserve">
|
||||
<value>Hinzufügen</value>
|
||||
</data>
|
||||
<data name="textDelete" xml:space="preserve">
|
||||
<value>Löschen</value>
|
||||
</data>
|
||||
<data name="textEdit" xml:space="preserve">
|
||||
<value>Bearbeiten</value>
|
||||
</data>
|
||||
<data name="textEditShips" xml:space="preserve">
|
||||
<value>Schiffe anlegen / bearbeiten</value>
|
||||
</data>
|
||||
<data name="textDeleted" xml:space="preserve">
|
||||
<value>Gelöscht</value>
|
||||
</data>
|
||||
<data name="textEditShip" xml:space="preserve">
|
||||
<value>Schiff bearbeiten</value>
|
||||
</data>
|
||||
<data name="textTugCompany" xml:space="preserve">
|
||||
<value>Schlepper-Reederei</value>
|
||||
</data>
|
||||
<data name="textChangeHistory" xml:space="preserve">
|
||||
<value>Verlauf</value>
|
||||
</data>
|
||||
<data name="textInfoChangePW" xml:space="preserve">
|
||||
<value>App Info anzeigen und Passwort ändern</value>
|
||||
</data>
|
||||
<data name="textShowHistory" xml:space="preserve">
|
||||
<value>Änderungshistorie der Anläufe anzeigen</value>
|
||||
</data>
|
||||
<data name="textMineOnly" xml:space="preserve">
|
||||
<value>nur eigene</value>
|
||||
</data>
|
||||
<data name="textOperation" xml:space="preserve">
|
||||
<value>Vorgang</value>
|
||||
</data>
|
||||
<data name="textParticipant" xml:space="preserve">
|
||||
<value>Teilnehmer</value>
|
||||
</data>
|
||||
<data name="textTimestamp" xml:space="preserve">
|
||||
<value>Zeitpunkt</value>
|
||||
</data>
|
||||
<data name="textFixedOrder" xml:space="preserve">
|
||||
<value>Als feste Bestellung vermerkt</value>
|
||||
</data>
|
||||
<data name="textTooltipSetFixedOrder" xml:space="preserve">
|
||||
<value>Als feste Bestellung vermerken</value>
|
||||
</data>
|
||||
<data name="textTooltipUnSetFixedOrder" xml:space="preserve">
|
||||
<value>Feste Bestellung zurücknehmen</value>
|
||||
</data>
|
||||
<data name="textTriggerManualRefresh" xml:space="preserve">
|
||||
<value>Manuelle Aktualisierung der Anläufe auslösen</value>
|
||||
</data>
|
||||
<data name="Arrival" xml:space="preserve">
|
||||
<value>Einkommend</value>
|
||||
</data>
|
||||
<data name="Departure" xml:space="preserve">
|
||||
<value>Ausgehend</value>
|
||||
</data>
|
||||
<data name="Shifting" xml:space="preserve">
|
||||
<value>Verholung</value>
|
||||
</data>
|
||||
<data name="Undefined" xml:space="preserve">
|
||||
<value>Unbekannt</value>
|
||||
</data>
|
||||
<data name="textShips" xml:space="preserve">
|
||||
<value>Schiffe</value>
|
||||
<data name="worker2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>worker2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="textPilots" xml:space="preserve">
|
||||
<value>Flusslotsen</value>
|
||||
<data name="arrow_right_blue" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>arrow_right_blue.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="textPortAuthority" xml:space="preserve">
|
||||
<value>Hafenamt</value>
|
||||
<data name="arrow_up_green" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>arrow_up_green.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="textShiftingSequence" xml:space="preserve">
|
||||
<value>Verhol. Nr.</value>
|
||||
</data>
|
||||
<data name="textClearAll" xml:space="preserve">
|
||||
<value>Alle Eintragungen zurücksetzen?</value>
|
||||
</data>
|
||||
<data name="textBothTideTimesNecessary" xml:space="preserve">
|
||||
<value>Beide Tidenzeiten sollten angegeben werden (von - bis)</value>
|
||||
</data>
|
||||
<data name="textEndValueBeforeStartValue" xml:space="preserve">
|
||||
<value>Endzeit liegt vor Startzeit</value>
|
||||
</data>
|
||||
<data name="textError" xml:space="preserve">
|
||||
<value>Error</value>
|
||||
</data>
|
||||
<data name="textETAInThePast" xml:space="preserve">
|
||||
<value>Zeitpunkt ETA liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textETDInThePast" xml:space="preserve">
|
||||
<value>Zeitpunkt ETD liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textLockTimeInThePast" xml:space="preserve">
|
||||
<value>Schleusenzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textOperationEndInThePast" xml:space="preserve">
|
||||
<value>Operation Endzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textOperationStartInThePast" xml:space="preserve">
|
||||
<value>Operation Startzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textTideTimesInThePast" xml:space="preserve">
|
||||
<value>Tidenzeit liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textWarning" xml:space="preserve">
|
||||
<value>Warnung</value>
|
||||
</data>
|
||||
<data name="textZoneEntryInThePast" xml:space="preserve">
|
||||
<value>Zeit Reviereintritt liegt in der Vergangenheit</value>
|
||||
</data>
|
||||
<data name="textTidalBothValues" xml:space="preserve">
|
||||
<value>Für das Tidenfenster müssen beide Zeiten angegeben werden</value>
|
||||
</data>
|
||||
<data name="textTooFarInTheFuture" xml:space="preserve">
|
||||
<value>Eine Zeiteingabe ist zu weit in der Zukunft</value>
|
||||
<data name="textStartTimeMissing" xml:space="preserve">
|
||||
<value>Wenn eine Ende-Zeit angegeben wird, muss auch eine Start-Zeit angegeben werden</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -589,4 +589,13 @@
|
||||
<data name="_lock" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>lock.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="arrow_right_blue" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="arrow_up_green" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="textStartTimeMissing" xml:space="preserve">
|
||||
<value>If an end time is set, a start time is also required</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -89,8 +89,7 @@
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width=".5*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<xctk:WatermarkTextBox x:Name="textBoxSearch" Grid.Column="0" Margin="2" Watermark="{x:Static p:Resources.textEnterKeyword}" PreviewTextInput="textBoxSearch_PreviewTextInput"
|
||||
DataObject.Pasting="textBoxSearch_Pasting" TextChanged="textBoxSearch_TextChanged" />
|
||||
<xctk:WatermarkTextBox x:Name="textBoxSearch" Grid.Column="0" Margin="2" Watermark="{x:Static p:Resources.textEnterKeyword}" TextChanged="textBoxSearch_TextChanged" />
|
||||
<CheckBox x:Name="checkBoxOwn" VerticalAlignment="Center" Grid.Column="1" HorizontalAlignment="Right" Margin="2" Checked="checkBoxOwn_Checked" Unchecked="checkBoxOwn_Checked" />
|
||||
<Label Content="{x:Static p:Resources.textMineOnly}" Grid.Column="2" />
|
||||
</Grid>
|
||||
|
||||
@ -185,21 +185,9 @@ namespace BreCalClient
|
||||
SearchFilterChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void textBoxSearch_Pasting(object sender, System.Windows.DataObjectPastingEventArgs e)
|
||||
{
|
||||
this.SearchFilter.SearchString = e.SourceDataObject.ToString();
|
||||
SearchFilterChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void textBoxSearch_PreviewTextInput(object sender, TextCompositionEventArgs e)
|
||||
{
|
||||
this.SearchFilter.SearchString = this.textBoxSearch.Text + e.Text;
|
||||
SearchFilterChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void textBoxSearch_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
this.SearchFilter.SearchString = this.textBoxSearch.Text;
|
||||
this.SearchFilter.SearchString = this.textBoxSearch.Text.Trim();
|
||||
SearchFilterChanged?.Invoke();
|
||||
}
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@ def create_app(test_config=None, instance_path=None):
|
||||
try:
|
||||
import os
|
||||
print(f'Instance path = {app.instance_path}')
|
||||
if not os.path.exists(app.instance_path):
|
||||
os.makedirs(app.instance_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
@ -6,6 +6,9 @@ import typing
|
||||
from BreCal.schemas.model import Shipcall, Ship, Participant, Berth, User, Times, ShipcallParticipantMap
|
||||
from BreCal.database.enums import ParticipantType
|
||||
from BreCal.local_db import getPoolConnection
|
||||
from BreCal.database.sql_queries import SQLQuery
|
||||
from BreCal.schemas import model
|
||||
|
||||
|
||||
def pandas_series_to_data_model():
|
||||
return
|
||||
@ -89,6 +92,13 @@ def execute_sql_query_standalone(query, param={}, pooledConnection=None, model=N
|
||||
schemas = commands.query_single_or_default(query, sentinel, param=param) if model is None else commands.query_single_or_default(query, sentinel, param=param, model=model)
|
||||
if schemas is sentinel:
|
||||
raise Exception("no such record")
|
||||
elif command_type=="single_or_none":
|
||||
sentinel = object()
|
||||
|
||||
# pulls a *single* row from the query. Typically, these queries require an ID within the param dictionary.
|
||||
# when providing a model, such as model.Shipcall, the dataset is immediately translated into a data model.
|
||||
schemas = commands.query_single_or_default(query, sentinel, param=param) if model is None else commands.query_single_or_default(query, sentinel, param=param, model=model)
|
||||
schemas = None if schemas is sentinel else schemas
|
||||
|
||||
elif command_type=="execute_scalar":
|
||||
schemas = commands.execute_scalar(query)
|
||||
@ -101,6 +111,26 @@ def execute_sql_query_standalone(query, param={}, pooledConnection=None, model=N
|
||||
pooledConnection.close()
|
||||
return schemas
|
||||
|
||||
def get_assigned_participant_of_type(shipcall_id:int, participant_type:typing.Union[int,model.ParticipantType])->typing.Optional[model.Participant]:
|
||||
"""obtains the ShipcallParticipantMap of a given shipcall and finds the participant id of a desired type. Finally, returns the respective Participant"""
|
||||
spm_shipcall_data = execute_sql_query_standalone(
|
||||
query=SQLQuery.get_shipcall_participant_map_by_shipcall_id_and_type(),
|
||||
param={"id":shipcall_id, "type":int(participant_type)},
|
||||
command_type="query") # returns a list of matches
|
||||
|
||||
if len(spm_shipcall_data)==0:
|
||||
return None
|
||||
|
||||
query = 'SELECT * FROM participant WHERE id=?participant_id?'
|
||||
assigned_participant = execute_sql_query_standalone(
|
||||
query=query,
|
||||
param={"participant_id":spm_shipcall_data[0]["participant_id"]},
|
||||
model=model.Participant,
|
||||
command_type="single_or_none"
|
||||
) # returns a list of matches
|
||||
return assigned_participant
|
||||
|
||||
|
||||
class SQLHandler():
|
||||
"""
|
||||
An object that reads SQL queries from the sql_connection and stores it in pandas DataFrames. The object can read all available tables
|
||||
|
||||
@ -12,3 +12,11 @@ def get_user_data_for_id(user_id:int, expiration_time:int=90):
|
||||
user_data["exp"] = (datetime.datetime.now()+datetime.timedelta(minutes=expiration_time)).timestamp()
|
||||
return user_data
|
||||
|
||||
|
||||
def get_times_data_for_id(times_id:int):
|
||||
"""helper function to load previous times data from the database"""
|
||||
query = "SELECT * FROM times where id = ?id?"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":times_id})
|
||||
pdata = pdata[0] if len(pdata)>0 else None
|
||||
assert pdata is not None, f"could not find times with id {times_id}"
|
||||
return pdata
|
||||
@ -74,7 +74,7 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
|
||||
|
||||
# existance checks in content
|
||||
# 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))
|
||||
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,17 +103,17 @@ 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
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ class InputValidationShip():
|
||||
ships = json.loads(response)
|
||||
|
||||
# extract only the 'imo' values
|
||||
ship_imos = [ship.get("imo") for ship in ships]
|
||||
ship_imos = [ship.get("imo") for ship in ships if not ship.get("deleted")]
|
||||
|
||||
# check, if the imo in the POST-request already exists in the list
|
||||
imo_already_exists = loadedModel.get("imo") in ship_imos
|
||||
|
||||
@ -12,6 +12,7 @@ from BreCal.impl.berths import GetBerths
|
||||
|
||||
from BreCal.database.enums import ParticipantType, ParticipantFlag
|
||||
from BreCal.validators.input_validation_utils import check_if_user_is_bsmd_type, check_if_ship_id_is_valid, check_if_berth_id_is_valid, check_if_participant_ids_are_valid, check_if_participant_ids_and_types_are_valid, get_shipcall_id_dictionary, get_participant_type_from_user_data
|
||||
from BreCal.database.sql_handler import get_assigned_participant_of_type
|
||||
from BreCal.database.sql_handler import execute_sql_query_standalone
|
||||
from BreCal.validators.validation_base_utils import check_if_int_is_valid_flag
|
||||
from BreCal.validators.validation_base_utils import check_if_string_has_special_characters
|
||||
@ -126,8 +127,7 @@ class InputValidationShipcall():
|
||||
if is_put_data:
|
||||
# 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)
|
||||
else:
|
||||
# time values must use future-dates
|
||||
|
||||
InputValidationShipcall.check_times_are_in_future(loadedModel, content)
|
||||
|
||||
# some arguments must not be provided
|
||||
@ -327,10 +327,10 @@ class InputValidationShipcall():
|
||||
def check_times_are_in_future(loadedModel:dict, content:dict):
|
||||
"""
|
||||
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
|
||||
@ -348,14 +348,14 @@ class InputValidationShipcall():
|
||||
tidal_window_to = loadedModel.get("tidal_window_to", None)
|
||||
|
||||
# Estimated arrival or departure times
|
||||
InputValidationShipcall.check_times_in_future_based_on_type(type_, time_now, eta, etd)
|
||||
InputValidationShipcall.check_times_in_future_based_on_type(type_, time_ref, eta, etd)
|
||||
|
||||
# Tidal Window
|
||||
InputValidationShipcall.check_tidal_window_in_future(type_, time_now, tidal_window_from, tidal_window_to)
|
||||
InputValidationShipcall.check_tidal_window_in_future(type_, time_ref, 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:
|
||||
@ -366,6 +366,8 @@ class InputValidationShipcall():
|
||||
if (eta is None) and (etd is None):
|
||||
return
|
||||
|
||||
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."})
|
||||
|
||||
@ -379,20 +381,24 @@ 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:
|
||||
raise ValidationError({"eta":f"'eta' is more than a year in the future. ETA: {eta}."})
|
||||
|
||||
elif int(type_)==int(ShipcallType.departure):
|
||||
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:
|
||||
raise ValidationError({"etd":f"'etd' is more than a year in the future. ETD: {etd}."})
|
||||
|
||||
elif int(type_)==int(ShipcallType.shifting):
|
||||
if (eta is None) and (etd is None): # null values -> no violation
|
||||
@ -403,28 +409,43 @@ 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}"})
|
||||
|
||||
if (eta is not None and etd is None) or (eta is None and etd is not None):
|
||||
raise ValidationError({"eta_or_etd":f"'eta' and 'etd' must both be provided when the shipcall type is 'shifting'."})
|
||||
if eta > time_in_a_year:
|
||||
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):
|
||||
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."})
|
||||
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
@ -465,6 +486,9 @@ class InputValidationShipcall():
|
||||
def check_shipcall_id_exists(loadedModel):
|
||||
"""simply checks, whether the defined shipcall ID exists in the database. Otherwise, a PUT-request must fail."""
|
||||
shipcall_id = loadedModel.get("id")
|
||||
if shipcall_id is None:
|
||||
raise ValidationError({"id":"a shipcall id must be provided"})
|
||||
|
||||
query = 'SELECT * FROM shipcall where (id = ?shipcall_id?)'
|
||||
shipcalls = execute_sql_query_standalone(query=query, model=Shipcall, param={"shipcall_id" : shipcall_id})
|
||||
if len(shipcalls)==0:
|
||||
@ -479,12 +503,12 @@ class InputValidationShipcall():
|
||||
a) belong to the ASSIGNED agency participant group
|
||||
b) belong to a BSMD participant, if the assigned agency has enabled the bit flag
|
||||
|
||||
When there is not yet an assigned agency for the respective shipcall, the request fails, and the user is considered as not authorized.
|
||||
When there is not yet an assigned agency for the respective shipcall, only BSMD users are authorized.
|
||||
This mechanism prevents self-assignment of an agency to arbitrary shipcalls.
|
||||
"""
|
||||
### preparation ###
|
||||
# use the decoded JWT token and extract the participant type & participant id
|
||||
participant_id = user_data.get("participant_id")
|
||||
user_participant_id = user_data.get("participant_id")
|
||||
participant_type = get_participant_type_from_user_data(user_data)
|
||||
user_is_bsmd = (ParticipantType.BSMD in participant_type)
|
||||
|
||||
@ -494,44 +518,42 @@ class InputValidationShipcall():
|
||||
### AGENCY in SPM ###
|
||||
# determine, who is assigned as the agency for the shipcall
|
||||
if shipcall_participant_map is None:
|
||||
query = 'SELECT * FROM shipcall_participant_map where (shipcall_id = ?shipcall_id? AND type=?participant_type?)'
|
||||
assigned_agency = execute_sql_query_standalone(query=query, model=ShipcallParticipantMap, param={"shipcall_id" : shipcall_id, "participant_type":int(ParticipantType.AGENCY)})
|
||||
else:
|
||||
assigned_agency = [spm for spm in shipcall_participant_map if int(spm.type) == int(ParticipantType.AGENCY)]
|
||||
# query = 'SELECT * FROM shipcall_participant_map where (shipcall_id = ?shipcall_id? AND type=?participant_type?)'
|
||||
# assigned_agency = execute_sql_query_standalone(query=query, model=ShipcallParticipantMap, param={"shipcall_id" : shipcall_id, "participant_type":int(ParticipantType.AGENCY)})
|
||||
assigned_agency = get_assigned_participant_of_type(shipcall_id, participant_type=ParticipantType.AGENCY)
|
||||
an_agency_is_assigned = True if assigned_agency is not None else False
|
||||
|
||||
else:
|
||||
# Agency assigned? User must belong to the assigned agency or be a BSMD user, in case the flag is set
|
||||
assigned_agency = [spm for spm in shipcall_participant_map if int(spm.type) == int(ParticipantType.AGENCY)]
|
||||
an_agency_is_assigned = len(assigned_agency)==1
|
||||
|
||||
if len(assigned_agency)>1:
|
||||
raise ValidationError({"internal_error":f"Internal error? Found more than one assigned agency for the shipcall with ID {shipcall_id}. Found: {assigned_agency}"})
|
||||
|
||||
if an_agency_is_assigned:
|
||||
# Agency assigned? User must belong to the assigned agency or be a BSMD user, in case the flag is set
|
||||
assigned_agency = assigned_agency[0]
|
||||
|
||||
# determine, whether the assigned agency has set the BSMD-flag to allow BSMD users to edit their assigned shipcalls
|
||||
query = 'SELECT * FROM participant where (id = ?participant_id?)'
|
||||
agency_participant = execute_sql_query_standalone(query=query, param={"participant_id" : participant_id}, command_type="single", model=Participant)
|
||||
if an_agency_is_assigned:
|
||||
assert isinstance(assigned_agency, Participant), f"expecting the assigency agency to be a Participant object. Found: {type(assigned_agency)}"
|
||||
assert isinstance(assigned_agency.flags, int), f"this method has currently only been developed with 'flags' being set as an integer. Found: {type(assigned_agency.flags)}"
|
||||
|
||||
assert isinstance(agency_participant.flags, int), f"this method has currently only been developed with 'flags' being set as an integer. Found: {type(agency_participant.flags)}"
|
||||
agency_has_bsmd_flag = agency_participant.flags==1 # once the flags are an IntFlag, change the boolean check to: (ParticipantFlag.BSMD in agency_participant.flags)
|
||||
# determine, whether the assigned agency has set the BSMD-flag to allow BSMD users to edit their assigned shipcalls
|
||||
agency_has_bsmd_flag = assigned_agency.flags==1 # once the flags are an IntFlag, change the boolean check to: (ParticipantFlag.BSMD in agency_participant.flags)
|
||||
|
||||
### USER authority ###
|
||||
# determine, whether the user is a) the assigned agency or b) a BSMD participant
|
||||
user_is_assigned_agency = (participant_id == assigned_agency.participant_id)
|
||||
user_is_assigned_agency = (user_participant_id == assigned_agency.id)
|
||||
|
||||
# when the BSMD flag is set: the user must be either BSMD or the assigned agency
|
||||
# when the BSMD flag is not set: the user must be the assigned agency
|
||||
user_is_authorized = (user_is_bsmd or user_is_assigned_agency) if agency_has_bsmd_flag else user_is_assigned_agency
|
||||
user_is_authorized = (user_is_bsmd or user_is_assigned_agency) #if agency_has_bsmd_flag else user_is_assigned_agency
|
||||
|
||||
if not user_is_authorized:
|
||||
raise werkzeug.exceptions.Forbidden(f"PUT Requests for shipcalls can only be issued by an assigned AGENCY or BSMD users (if the special-flag is enabled). Assigned Agency: {assigned_agency} with Flags: {agency_participant.flags}") # Forbidden: 403
|
||||
raise werkzeug.exceptions.Forbidden(f"PUT Requests for shipcalls can only be issued by an assigned AGENCY or BSMD users (if the special-flag is enabled). Assigned Agency: {assigned_agency} with Flags: {assigned_agency.flags}") # Forbidden: 403
|
||||
|
||||
else:
|
||||
# when there is no assigned agency, only BSMD users can update the shipcall
|
||||
user_is_authorized = user_is_bsmd
|
||||
|
||||
if not user_is_authorized:
|
||||
if not user_is_bsmd:
|
||||
raise werkzeug.exceptions.Forbidden(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.") # part of a pytest.raises. Forbidden: 403
|
||||
|
||||
return
|
||||
|
||||
|
||||
@ -15,6 +15,8 @@ from BreCal.database.enums import ParticipantType, ParticipantFlag
|
||||
from BreCal.validators.input_validation_utils import check_if_user_is_bsmd_type, check_if_ship_id_is_valid, check_if_berth_id_is_valid, check_if_participant_ids_are_valid, check_if_participant_ids_and_types_are_valid, check_if_shipcall_id_is_valid, get_shipcall_id_dictionary, get_participant_type_from_user_data, get_participant_id_dictionary, check_if_participant_id_is_valid_standalone
|
||||
from BreCal.database.sql_queries import SQLQuery
|
||||
from BreCal.database.sql_handler import execute_sql_query_standalone
|
||||
from BreCal.database.sql_handler import get_assigned_participant_of_type
|
||||
from BreCal.database.sql_utils import get_times_data_for_id
|
||||
from BreCal.validators.validation_base_utils import check_if_int_is_valid_flag, check_if_string_has_special_characters
|
||||
import werkzeug
|
||||
|
||||
@ -97,6 +99,10 @@ class InputValidationTimes():
|
||||
# 1.) Check for the presence of required fields
|
||||
InputValidationTimes.check_times_required_fields_put_data(content)
|
||||
|
||||
# 1.5) Load model from database and set existing fields from dict to model
|
||||
old_times = get_times_data_for_id(content["id"])
|
||||
loadedModel = {**old_times, **loadedModel}
|
||||
|
||||
# 2.) Only users of the same participant_id, which the times dataset refers to, can update the entry
|
||||
InputValidationTimes.check_user_belongs_to_same_group_as_dataset_determines(user_data, loadedModel=loadedModel, times_id=None)
|
||||
|
||||
@ -118,6 +124,7 @@ class InputValidationTimes():
|
||||
InputValidationTimes.check_if_entry_is_already_deleted(times_id)
|
||||
|
||||
# 2.) Only users of the same participant_id, which the times dataset refers to, can delete the entry
|
||||
if not check_if_user_is_bsmd_type(user_data):
|
||||
InputValidationTimes.check_user_belongs_to_same_group_as_dataset_determines(user_data, loadedModel=None, times_id=times_id)
|
||||
return
|
||||
|
||||
@ -167,12 +174,12 @@ class InputValidationTimes():
|
||||
if ParticipantType.BSMD in loadedModel["participant_type"]:
|
||||
raise ValidationError({"participant_type":f"current user belongs to BSMD. Cannot post times datasets. Found user data: {user_data}"})
|
||||
|
||||
if (loadedModel["etd_interval_end"] is not None) and (loadedModel["etd_berth"] is not None):
|
||||
if ("etd_interval_end" in loadedModel and loadedModel["etd_interval_end"] is not None) and ("etd_berth" in loadedModel and loadedModel["etd_berth"] is not None):
|
||||
time_end_after_time_start = loadedModel["etd_interval_end"] >= loadedModel["etd_berth"]
|
||||
if not time_end_after_time_start:
|
||||
raise ValidationError({"etd":f"The provided time interval for the estimated departure time is invalid. The interval end takes place before the interval start. Found interval data: {loadedModel['etd_berth']} to {loadedModel['etd_interval_end']}"})
|
||||
|
||||
if (loadedModel["eta_interval_end"] is not None) and (loadedModel["eta_berth"] is not None):
|
||||
if ("eta_interval_end" in loadedModel and loadedModel["eta_interval_end"] is not None) and ("eta_berth" in loadedModel and loadedModel["eta_berth"] is not None):
|
||||
time_end_after_time_start = loadedModel["eta_interval_end"] >= loadedModel["eta_berth"]
|
||||
if not time_end_after_time_start:
|
||||
raise ValidationError({"eta":f"The provided time interval for the estimated arrival time is invalid. The interval begin takes place after the interval end. Found interval data: {loadedModel['eta_berth']} to {loadedModel['eta_interval_end']}"})
|
||||
@ -379,45 +386,69 @@ class InputValidationTimes():
|
||||
# identify the user's participant id
|
||||
user_participant_id = user_data["participant_id"]
|
||||
|
||||
""" # #TODO:
|
||||
First of all, this method is shared for PUT and DELETE requests.
|
||||
PUT) is based on the loadedModel
|
||||
DELETE) is based on the times_id
|
||||
Both of them share the {user_data}-argument
|
||||
|
||||
These arguments are used to obtain shipcall_id, participant_type (of the times entry) and times_assigned_participant
|
||||
|
||||
there should be the following authorization approaches
|
||||
a) the user has the participant ID of the assigned entry for a given role
|
||||
for this, we need:
|
||||
1) user_participant_id
|
||||
2) times_participant_type
|
||||
3) SPM: assigned participant of the respective type (times_assigned_participant)
|
||||
_ = get_assigned_participant_of_type(shipcall_id, participant_type=ParticipantType.WHATTYPE)
|
||||
|
||||
b) the user is the assigned agency (or the BSMD if allowed)
|
||||
for this, we need:
|
||||
1) assigned_agency
|
||||
assigned_agency = get_assigned_participant_of_type(shipcall_id, participant_type=ParticipantType.AGENCY)
|
||||
2) agency's flag
|
||||
assigned_agency.flags
|
||||
3) user_is_bsmd boolean
|
||||
"""
|
||||
|
||||
# commonly used in the PUT-request
|
||||
if loadedModel is not None:
|
||||
shipcall_id = loadedModel["shipcall_id"]
|
||||
participant_type = loadedModel["participant_type"]
|
||||
|
||||
# get the matching entry from the shipcall participant map. Raise an error, when there is no match.
|
||||
participant_id_of_times_dataset = InputValidationTimes.get_participant_id_from_shipcall_participant_map(shipcall_id, participant_type)
|
||||
(shipcall_id, times_assigned_participant) = InputValidationTimes.prepare_authority_check_for_put_request(loadedModel)
|
||||
|
||||
# commonly used in the DELETE-request
|
||||
if times_id is not None:
|
||||
if pdata is None: # regular behavior. pdata is only defined in unit tests.
|
||||
# perform an SQL query. Creates a pooled connection internally, queries the database, then closes the connection.
|
||||
query = "SELECT participant_id, participant_type, shipcall_id FROM times WHERE id = ?id?"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":times_id}, pooledConnection=None)
|
||||
# #TODO_refactor:
|
||||
(shipcall_id, times_assigned_participant) = InputValidationTimes.prepare_authority_check_for_delete_request(times_id, pdata)
|
||||
|
||||
# extracts the participant_id from the first matching entry, if applicable
|
||||
if not len(pdata)>0:
|
||||
# this case is usually covered by the InputValidationTimes.check_if_entry_is_already_deleted method already
|
||||
raise ValidationError({"times_id":f"Unknown times_id. Could not find a matching entry for ID: {times_id}"})
|
||||
else:
|
||||
participant_type = pdata[0].get("participant_type")
|
||||
shipcall_id = pdata[0].get("shipcall_id")
|
||||
# get the matching entry from the shipcall participant map, where the role matches. Raise an error, when there is no match.
|
||||
assigned_agency = get_assigned_participant_of_type(shipcall_id, participant_type=ParticipantType.AGENCY)
|
||||
|
||||
# get the matching entry from the shipcall participant map. Raise an error, when there is no match.
|
||||
participant_id_of_times_dataset = pdata[0].get("participant_id")
|
||||
# participant_id_of_times_dataset = InputValidationTimes.get_participant_id_from_shipcall_participant_map(shipcall_id, participant_type)
|
||||
# a) the user has the participant ID of the assigned entry for a given role
|
||||
user_is_assigned_role = user_participant_id == times_assigned_participant.id
|
||||
|
||||
# when the user's participant id is different from the times dataset, an exception is raised
|
||||
if user_participant_id != participant_id_of_times_dataset:
|
||||
# for some AGENCY participants, users with the BSMD flag may also edit the datasets
|
||||
special_case__bsmd_may_edit_agency_dataset = InputValidationTimes.check_if_bsmd_may_edit_agency_dataset(user_participant_id, participant_id_of_times_dataset, participant_type)
|
||||
if special_case__bsmd_may_edit_agency_dataset:
|
||||
# b) the user is the assigned agency
|
||||
user_is_assigned_agency = user_participant_id == assigned_agency.id
|
||||
|
||||
# c) the user is BSMD, if the assigned agency allows that
|
||||
assigned_agency_has_bsmd_flag = assigned_agency.flags == 1
|
||||
user_is_bsmd_type = check_if_user_is_bsmd_type(user_data={"participant_id":user_participant_id})
|
||||
user_is_bsmd_and_assigned_agency_has_flag = assigned_agency_has_bsmd_flag & user_is_bsmd_type
|
||||
|
||||
if user_is_assigned_role:
|
||||
return
|
||||
else:
|
||||
raise ValidationError({"user_participant_type":f"The dataset may only be changed by a user belonging to the same participant group as the times dataset is referring to. User participant_id: {user_participant_id}; Dataset participant_id: {participant_id_of_times_dataset}"})
|
||||
|
||||
elif user_is_assigned_agency:
|
||||
return
|
||||
|
||||
elif user_is_bsmd_and_assigned_agency_has_flag:
|
||||
return
|
||||
|
||||
else:
|
||||
times_participant_id = loadedModel.get("participant_id")
|
||||
raise ValidationError({"user_participant_type": f"The dataset may only be changed by a user belonging to the same participant group as the times dataset is referring to. Alternatively, the assigned agency may edit and delete the dataset. As a special case, BSMD users may edit and delete times datasets, when the assigned agency allows that. User participant_id: {user_participant_id}; Dataset participant_id: {times_participant_id}"})
|
||||
|
||||
@staticmethod
|
||||
def get_participant_id_from_shipcall_participant_map(shipcall_id:int, participant_type:int, spm_shipcall_data=None)->int:
|
||||
def get_participant_id_from_shipcall_participant_map(shipcall_id:typing.Optional[int], participant_type:int, spm_shipcall_data=None)->int:
|
||||
"""use shipcall_id and participant_type to identify the matching participant_id"""
|
||||
if shipcall_id is None:
|
||||
raise ValidationError({"shipcall_id":f"Could not find a referenced shipcall_id within the request."})
|
||||
@ -480,6 +511,42 @@ class InputValidationTimes():
|
||||
has_bsmd_flag = ParticipantFlag.BSMD in [ParticipantFlag(participant.get("flags"))]
|
||||
return has_bsmd_flag
|
||||
|
||||
@staticmethod
|
||||
def prepare_authority_check_for_put_request(loadedModel)->typing.Tuple[int,Participant]:
|
||||
"""extracts the loadedModel to obtain relevant arguments"""
|
||||
shipcall_id = loadedModel["shipcall_id"]
|
||||
participant_type = loadedModel["participant_type"]
|
||||
|
||||
# get the matching entry from the shipcall participant map, where the role matches. Raise an error, when there is no match.
|
||||
times_assigned_participant = get_assigned_participant_of_type(shipcall_id, participant_type=participant_type)
|
||||
|
||||
if times_assigned_participant is None:
|
||||
raise ValidationError({"participant_type":"the requested participant type is not assigned to the shipcall."})
|
||||
return (shipcall_id, times_assigned_participant)
|
||||
|
||||
@staticmethod
|
||||
def prepare_authority_check_for_delete_request(times_id, pdata=None)->typing.Tuple[int,Participant]:
|
||||
if pdata is None: # regular behavior. pdata is only defined in unit tests.
|
||||
# perform an SQL query. Creates a pooled connection internally, queries the database, then closes the connection.
|
||||
query = "SELECT participant_id, participant_type, shipcall_id FROM times WHERE id = ?id?"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":times_id}, pooledConnection=None)
|
||||
|
||||
# extracts the participant_id from the first matching entry, if applicable
|
||||
if not len(pdata)>0:
|
||||
# this case is usually covered by the InputValidationTimes.check_if_entry_is_already_deleted method already
|
||||
raise ValidationError({"times_id":f"Unknown times_id. Could not find a matching entry for ID: {times_id}"})
|
||||
else:
|
||||
participant_type = pdata[0].get("participant_type")
|
||||
shipcall_id = pdata[0].get("shipcall_id")
|
||||
|
||||
# get the matching entry from the shipcall participant map, where the role matches. Raise an error, when there is no match.
|
||||
times_assigned_participant = get_assigned_participant_of_type(shipcall_id, participant_type=participant_type)
|
||||
|
||||
if times_assigned_participant is None:
|
||||
raise ValidationError({"participant_type":"the requested participant type is not assigned to the shipcall."})
|
||||
return (shipcall_id, times_assigned_participant)
|
||||
|
||||
|
||||
|
||||
def deprecated_build_post_data_type_dependent_required_fields_dict()->dict[ShipcallType,dict[ParticipantType,typing.Optional[list[str]]]]:
|
||||
"""
|
||||
|
||||
@ -41,7 +41,7 @@ def unbundle_validation_error_message(message):
|
||||
unbundle_(message, unbundled=unbundled)
|
||||
if len(unbundled)>0:
|
||||
error_field = "ValidationError in the following field(s): " + " & ".join([unb["error_field"] for unb in unbundled])
|
||||
error_description = "Error Description(s): " + " & ".join([unb["error_description"] for unb in unbundled])
|
||||
error_description = " " . join([unb["error_description"] for unb in unbundled])
|
||||
else:
|
||||
error_field = "ValidationError"
|
||||
error_description = "unknown validation error"
|
||||
|
||||
@ -3,7 +3,7 @@ import sys
|
||||
import logging
|
||||
|
||||
sys.path.insert(0, '/var/www/brecal_test/src/server')
|
||||
sys.path.insert(0, '/var/www/venv/lib/python3.10/site-packages/')
|
||||
sys.path.insert(0, '/var/www/venv/lib/python3.12/site-packages/')
|
||||
|
||||
import schedule
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user