Merge branch 'release/1.6.0'
This commit is contained in:
commit
3f37ee67e5
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
23
misc/clear_entries_for_participant.sql
Normal file
23
misc/clear_entries_for_participant.sql
Normal file
@ -0,0 +1,23 @@
|
||||
DELETE FROM times WHERE
|
||||
times.shipcall_id IN
|
||||
(
|
||||
SELECT s.id FROM shipcall s
|
||||
JOIN shipcall_participant_map spm ON s.id = spm.shipcall_id
|
||||
JOIN participant p ON spm.participant_id = p.id
|
||||
WHERE p.id = 10
|
||||
);
|
||||
|
||||
DELETE `history` FROM `history`
|
||||
JOIN shipcall s on `history`.shipcall_id = s.id
|
||||
JOIN shipcall_participant_map spm ON s.id = spm.shipcall_id
|
||||
WHERE spm.participant_id = 10;
|
||||
|
||||
-- damit das hier funktioniert muss der FK in shipcall_participant_map von "RESTRICT" auf "SET NULL"
|
||||
-- geändert werden
|
||||
|
||||
DELETE shipcall FROM shipcall
|
||||
INNER JOIN shipcall_participant_map spm ON shipcall.id = spm.shipcall_id
|
||||
JOIN participant p ON spm.participant_id = p.id
|
||||
WHERE p.id = 10;
|
||||
|
||||
DELETE FROM shipcall_participant_map WHERE participant_id = 10;
|
||||
37
misc/requirements.txt
Normal file
37
misc/requirements.txt
Normal file
@ -0,0 +1,37 @@
|
||||
bcrypt==4.2.0
|
||||
blinker==1.8.2
|
||||
cached-property==1.5.2
|
||||
click==8.1.7
|
||||
coro-context-manager==0.2.0
|
||||
coverage==7.6.1
|
||||
dsnparse==0.1.15
|
||||
Flask==3.0.3
|
||||
Flask-JWT-Extended==4.6.0
|
||||
iniconfig==2.0.0
|
||||
itsdangerous==2.2.0
|
||||
Jinja2==3.1.4
|
||||
MarkupSafe==2.1.5
|
||||
marshmallow==3.22.0
|
||||
marshmallow-enum==1.5.1
|
||||
marshmallow_dataclass==8.7.1
|
||||
mypy-extensions==1.0.0
|
||||
mysql-connector-python==9.0.0
|
||||
numpy==2.1.1
|
||||
packaging==24.1
|
||||
pandas==2.2.3
|
||||
pluggy==1.5.0
|
||||
pydapper==0.10.0
|
||||
PyJWT==2.9.0
|
||||
pytest==8.3.3
|
||||
pytest-cov==5.0.0
|
||||
python-dateutil==2.9.0.post0
|
||||
pytz==2024.2
|
||||
schedule==1.2.2
|
||||
six==1.16.0
|
||||
tqdm==4.66.5
|
||||
typeguard==4.3.0
|
||||
typing-inspect==0.9.0
|
||||
typing_extensions==4.12.2
|
||||
tzdata==2024.1
|
||||
webargs==8.6.0
|
||||
Werkzeug==3.0.4
|
||||
57
misc/update_1.5_to_1.6.sql
Normal file
57
misc/update_1.5_to_1.6.sql
Normal file
@ -0,0 +1,57 @@
|
||||
CREATE TABLE `port` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(128) NOT NULL COMMENT 'Name of port',
|
||||
`locode` char(5) DEFAULT NULL COMMENT 'UNECE locode',
|
||||
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted` bit(1) DEFAULT b'0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Port as reference for shipcalls and berths';
|
||||
|
||||
-- Add default port to table
|
||||
INSERT INTO port (id, name, locode) VALUES (1, 'Bremen', 'DEBRE');
|
||||
|
||||
-- Adding new ref column to berth
|
||||
ALTER TABLE `berth`
|
||||
ADD COLUMN `port_id` INT UNSIGNED DEFAULT NULL AFTER `authority_id`;
|
||||
ALTER TABLE `berth` ALTER INDEX `FK_AUTHORITY_PART_idx` INVISIBLE;
|
||||
|
||||
-- adding a foreign key berth.port_id -> port.id
|
||||
ALTER TABLE `berth`
|
||||
ADD INDEX `FK_PORT_PART_idx` (`port_id` ASC) VISIBLE;
|
||||
|
||||
ALTER TABLE `berth`
|
||||
ADD CONSTRAINT `FK_PORT`
|
||||
FOREIGN KEY (`port_id`)
|
||||
REFERENCES `port` (`id`)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE RESTRICT;
|
||||
|
||||
-- adding new ref column to shipcall incl. foreign key
|
||||
ALTER TABLE `shipcall`
|
||||
ADD COLUMN `port_id` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Selected port for this shipcall' AFTER `evaluation_notifications_sent`,
|
||||
CHANGE COLUMN `time_ref_point` `time_ref_point` INT NULL DEFAULT '0' COMMENT 'Index of a location which is the reference point for all time value entries, e.g. berth or Geeste' AFTER `port_id`,
|
||||
ADD INDEX `FK_SHIPCALL_PORT_idx` (`port_id` ASC) VISIBLE;
|
||||
;
|
||||
ALTER TABLE `shipcall`
|
||||
ADD CONSTRAINT `FK_SHIPCALL_PORT`
|
||||
FOREIGN KEY (`port_id`)
|
||||
REFERENCES `port` (`id`)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE RESTRICT;
|
||||
|
||||
CREATE TABLE `participant_port_map` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`participant_id` int unsigned NOT NULL COMMENT 'Ref to participant',
|
||||
`port_id` int unsigned NOT NULL COMMENT 'Ref to port',
|
||||
`created` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `FK_PP_PARTICIPANT` (`participant_id`),
|
||||
KEY `FK_PP_PORT` (`port_id`),
|
||||
CONSTRAINT `FK_PP_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`),
|
||||
CONSTRAINT `FK_PP_PORT` FOREIGN KEY (`port_id`) REFERENCES `port` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Mapping table that assigns participants to a port';
|
||||
|
||||
-- all existing berths shall default to "bremen"
|
||||
UPDATE berth SET port_id = 1 where port_id is null;
|
||||
@ -1 +1 @@
|
||||
1.4.1.0
|
||||
1.6.0.8
|
||||
@ -8,8 +8,8 @@
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<StartupObject>BreCalClient.App</StartupObject>
|
||||
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
|
||||
<AssemblyVersion>1.5.0.12</AssemblyVersion>
|
||||
<FileVersion>1.5.0.12</FileVersion>
|
||||
<AssemblyVersion>1.6.0.8</AssemblyVersion>
|
||||
<FileVersion>1.6.0.8</FileVersion>
|
||||
<Title>Bremen calling client</Title>
|
||||
<Description>A Windows WPF client for the Bremen calling API.</Description>
|
||||
<ApplicationIcon>containership.ico</ApplicationIcon>
|
||||
|
||||
@ -25,16 +25,19 @@ namespace BreCalClient
|
||||
private static List<Participant> _participants = new();
|
||||
private static readonly List<ShipModel> _ships = new();
|
||||
private static readonly List<ShipModel> _allShips = new();
|
||||
private static readonly List<Port> _ports = new();
|
||||
private static readonly List<Port> _allPorts = new();
|
||||
|
||||
private readonly static ConcurrentDictionary<int, ShipModel> _shipLookupDict = new();
|
||||
private readonly static ConcurrentDictionary<int, Berth> _berthLookupDict = new();
|
||||
private readonly static Dictionary<int, Participant> _participantLookupDict = new();
|
||||
private readonly static ConcurrentDictionary<int, Port> _portLookupDict = new();
|
||||
|
||||
/// <summary>
|
||||
/// List of TimeRef points
|
||||
/// </summary>
|
||||
// TODO: To make this portable the list of texts should come from a configuration file
|
||||
private readonly static List<string> _timeRefs = new List<string>
|
||||
private readonly static List<string> _timeRefs = new()
|
||||
{
|
||||
"ETB",
|
||||
"Geeste",
|
||||
@ -45,12 +48,26 @@ namespace BreCalClient
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// fast ship lookup
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<int, ShipModel> ShipLookupDict { get { return _shipLookupDict; } }
|
||||
|
||||
/// <summary>
|
||||
/// fast port lookup
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<int, Berth> BerthLookupDict { get { return _berthLookupDict; } }
|
||||
|
||||
/// <summary>
|
||||
/// fast participant lookup
|
||||
/// </summary>
|
||||
public static Dictionary<int, Participant> ParticipantLookupDict { get { return _participantLookupDict; } }
|
||||
|
||||
/// <summary>
|
||||
/// fast port lookup
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<int, Port> PortLookupDict { get { return _portLookupDict; } }
|
||||
|
||||
/// <summary>
|
||||
/// Participants that are agents
|
||||
/// </summary>
|
||||
@ -91,6 +108,16 @@ namespace BreCalClient
|
||||
/// </summary>
|
||||
public static List<Berth> AllBerths { get { return _allBerths; } }
|
||||
|
||||
/// <summary>
|
||||
/// All active ports
|
||||
/// </summary>
|
||||
public static List<Port> Ports { get { return _ports; } }
|
||||
|
||||
/// <summary>
|
||||
/// All ports including deleted ports
|
||||
/// </summary>
|
||||
public static List<Port> AllPorts { get { return _allPorts; } }
|
||||
|
||||
/// <summary>
|
||||
/// All active ships
|
||||
/// </summary>
|
||||
@ -108,7 +135,33 @@ namespace BreCalClient
|
||||
|
||||
#endregion
|
||||
|
||||
#region methods
|
||||
#region public static methods
|
||||
|
||||
public static List<Berth> GetBerthsByPort(int port)
|
||||
{
|
||||
List<Berth> berths = new();
|
||||
foreach(Berth berth in _berths)
|
||||
{
|
||||
if(berth.PortId == port)
|
||||
berths.Add(berth);
|
||||
}
|
||||
return berths;
|
||||
}
|
||||
|
||||
public static List<Participant> GetParticipants(int port, Extensions.ParticipantType type)
|
||||
{
|
||||
List<Participant> participants = new();
|
||||
foreach(Participant participant in _participants)
|
||||
{
|
||||
if(participant.IsTypeFlagSet(type) && participant.Ports.Contains(port))
|
||||
participants.Add(participant);
|
||||
}
|
||||
return participants;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal initializer methods
|
||||
|
||||
internal static void InitializeParticipants(List<Participant> participants)
|
||||
{
|
||||
@ -157,6 +210,17 @@ namespace BreCalClient
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InitializePorts(List<Port> ports)
|
||||
{
|
||||
foreach(var port in ports)
|
||||
{
|
||||
_portLookupDict[port.Id] = port;
|
||||
if(!port.Deleted)
|
||||
_ports.Add(port);
|
||||
_allPorts.Add(port);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@ -44,7 +44,9 @@
|
||||
<xctk:DoubleUpDown x:Name="doubleUpDownWidth" Margin="2" Grid.Column="1" Grid.Row="4" FormatString="N2" IsReadOnly="True" IsEnabled="False" ShowButtonSpinner="False"/>
|
||||
<Label Content="{x:Static p:Resources.textCancelled}" Grid.Column="0" Grid.Row="5" HorizontalContentAlignment="Right" />
|
||||
<CheckBox x:Name="checkBoxCancelled" Grid.Column="1" Grid.Row="5" Margin="2" VerticalContentAlignment="Center" />
|
||||
<Button x:Name="buttonEditShips" Grid.Column="1" Grid.Row="6" Margin="2" Content="{x:Static p:Resources.textEditShips}" Click="buttonEditShips_Click" Visibility="Hidden" />
|
||||
<Label Content="{x:Static p:Resources.textHarbour}" Grid.Column="0" Grid.Row="6" HorizontalContentAlignment="Right" />
|
||||
<ComboBox x:Name="comboBoxHarbour" Grid.Column="1" Margin="2" Grid.Row="6" DisplayMemberPath="Name" SelectedValuePath="Id" />
|
||||
<Button x:Name="buttonEditShips" Grid.Column="1" Grid.Row="7" Margin="2" Content="{x:Static p:Resources.textEditShips}" Click="buttonEditShips_Click" Visibility="Hidden" />
|
||||
|
||||
<Label Content="{x:Static p:Resources.textType}" Grid.Column="2" Grid.Row="0" HorizontalContentAlignment="Right" />
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ using BreCalClient.misc.Api;
|
||||
using BreCalClient.misc.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using static BreCalClient.Extensions;
|
||||
@ -41,13 +42,14 @@ namespace BreCalClient
|
||||
|
||||
public ShipApi? ShipApi { get; set; }
|
||||
|
||||
public bool IsCreate { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handler
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxAgency.ItemsSource = BreCalLists.Participants_Agent;
|
||||
{
|
||||
|
||||
this.comboBoxShip.ItemsSource = BreCalLists.Ships;
|
||||
Array types = Enum.GetValues(typeof(ShipcallType));
|
||||
@ -59,10 +61,8 @@ namespace BreCalClient
|
||||
else first = false;
|
||||
}
|
||||
|
||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
|
||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
|
||||
|
||||
this.comboBoxTimeRef.ItemsSource = BreCalLists.TimeRefs;
|
||||
this.comboBoxHarbour.ItemsSource = BreCalLists.Ports.Where(x => App.Participant.Ports.Contains(x.Id));
|
||||
|
||||
this.integerUpDownShiftingCount.Value = this.ShipcallModel.ShiftSequence;
|
||||
|
||||
@ -86,21 +86,21 @@ namespace BreCalClient
|
||||
}
|
||||
|
||||
private void comboBoxShip_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
{
|
||||
if (this.comboBoxShip.SelectedItem != null)
|
||||
{
|
||||
ShipModel? ship = this.comboBoxShip.SelectedItem as ShipModel;
|
||||
this.integerUpDownIMO.Value = ship?.Ship.Imo;
|
||||
this.textBoxCallsign.Text = ship?.Ship.Callsign;
|
||||
this.doubleUpDownLength.Value = ship?.Ship.Length;
|
||||
this.doubleUpDownWidth.Value = ship?.Ship.Width;
|
||||
this.doubleUpDownWidth.Value = ship?.Ship.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.integerUpDownIMO.Value = null;
|
||||
this.textBoxCallsign.Text = string.Empty;
|
||||
this.doubleUpDownLength.Value = null;
|
||||
this.doubleUpDownWidth.Value = null;
|
||||
this.doubleUpDownWidth.Value = null;
|
||||
}
|
||||
this.CheckForCompletion();
|
||||
}
|
||||
@ -118,7 +118,7 @@ namespace BreCalClient
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ShipcallType.Arrival:
|
||||
case ShipcallType.Arrival:
|
||||
this.datePickerETD.Visibility = Visibility.Hidden;
|
||||
this.labelETD.Visibility = Visibility.Hidden;
|
||||
this.datePickerETA.Visibility = Visibility.Visible;
|
||||
@ -175,7 +175,7 @@ namespace BreCalClient
|
||||
this.comboBoxAgency.SelectedIndex = -1;
|
||||
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.AGENCY);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region private methods
|
||||
@ -188,10 +188,13 @@ namespace BreCalClient
|
||||
|
||||
void CheckForCompletion()
|
||||
{
|
||||
if (this.ShipcallModel.Shipcall?.Canceled ?? false) return; // Cancelled shipcall never clicks ok
|
||||
|
||||
bool isEnabled = true;
|
||||
|
||||
isEnabled &= this.comboBoxShip.SelectedItem != null;
|
||||
isEnabled &= this.comboBoxCategories.SelectedItem != null;
|
||||
isEnabled &= this.comboBoxHarbour.SelectedItem != null;
|
||||
|
||||
if (comboBoxCategories.SelectedItem == null)
|
||||
{
|
||||
@ -207,7 +210,7 @@ namespace BreCalClient
|
||||
isEnabled &= this.datePickerETD.Value.HasValue;
|
||||
isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
|
||||
isEnabled &= !this.datePickerETD.Value.IsTooFar();
|
||||
break;
|
||||
break;
|
||||
case ShipcallType.Arrival:
|
||||
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
|
||||
isEnabled &= this.datePickerETA.Value.HasValue;
|
||||
@ -227,7 +230,7 @@ namespace BreCalClient
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isEnabled &= this.comboBoxAgency.SelectedItem != null;
|
||||
|
||||
this.buttonOK.IsEnabled = isEnabled;
|
||||
@ -249,7 +252,7 @@ namespace BreCalClient
|
||||
{
|
||||
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
|
||||
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
|
||||
}
|
||||
}
|
||||
else // shifting
|
||||
{
|
||||
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
|
||||
@ -264,11 +267,11 @@ namespace BreCalClient
|
||||
ParticipantAssignment pa = new()
|
||||
{
|
||||
ParticipantId = participant.Id,
|
||||
|
||||
|
||||
Type = (int)Extensions.ParticipantType.AGENCY
|
||||
};
|
||||
this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.AGENCY] = pa;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// AGENCY was set before and now is set to nothing
|
||||
@ -309,7 +312,7 @@ namespace BreCalClient
|
||||
|
||||
// set the time reference value (which point do all times refer to?)
|
||||
this.ShipcallModel.Shipcall.TimeRefPoint = this.comboBoxTimeRef.SelectedIndex;
|
||||
|
||||
this.ShipcallModel.Shipcall.PortId = ((Port) this.comboBoxHarbour.SelectedItem).Id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,8 +324,8 @@ namespace BreCalClient
|
||||
this.comboBoxTimeRef.SelectedIndex = this.ShipcallModel.Shipcall.TimeRefPoint ?? 1;
|
||||
this.comboBoxCategories.SelectedItem = new EnumToStringConverter().Convert(this.ShipcallModel.Shipcall.Type, typeof(ShipcallType), new object(), System.Globalization.CultureInfo.CurrentCulture);
|
||||
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
|
||||
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
||||
// this.textBoxVoyage.Text = this.ShipcallModel.Shipcall.Voyage;
|
||||
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
||||
|
||||
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
|
||||
if (BreCalLists.Ships.Find(x => x.Ship.Id == this.ShipcallModel.Shipcall.ShipId) != null)
|
||||
{
|
||||
@ -333,6 +336,16 @@ namespace BreCalClient
|
||||
}
|
||||
this.checkBoxCancelled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
||||
|
||||
if (BreCalLists.PortLookupDict.ContainsKey(this.ShipcallModel.Shipcall.PortId))
|
||||
this.comboBoxHarbour.SelectedValue = this.ShipcallModel.Shipcall.PortId;
|
||||
List<Berth> availableBerths = BreCalLists.GetBerthsByPort(this.ShipcallModel.Shipcall.PortId);
|
||||
this.comboBoxArrivalBerth.ItemsSource = availableBerths;
|
||||
this.comboBoxDepartureBerth.ItemsSource = availableBerths;
|
||||
|
||||
// Filter agency combobox by port
|
||||
List<Participant> availableAgencies = BreCalLists.GetParticipants(this.ShipcallModel.Shipcall.PortId, ParticipantType.AGENCY);
|
||||
this.comboBoxAgency.ItemsSource = availableAgencies;
|
||||
|
||||
if (this.ShipcallModel.Shipcall.Type != ShipcallType.Shifting) // incoming, outgoing
|
||||
{
|
||||
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
|
||||
@ -345,14 +358,18 @@ namespace BreCalClient
|
||||
}
|
||||
|
||||
if (this.ShipcallModel.Shipcall.Participants == null) this.ShipcallModel.Shipcall.Participants = new();
|
||||
|
||||
|
||||
if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
{
|
||||
if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId))
|
||||
{
|
||||
this.comboBoxAgency.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.comboBoxHarbour.SelectionChanged += this.comboBoxHarbour_SelectionChanged;
|
||||
|
||||
this.comboBoxHarbour.IsEnabled = this.ShipcallModel.AllowPortChange;
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,6 +380,8 @@ namespace BreCalClient
|
||||
|
||||
bool editRightGrantedForBSMD = false;
|
||||
|
||||
if (this.ShipcallModel.Shipcall?.Canceled ?? false) return; // do not allow edit on canceled shipcall
|
||||
|
||||
// Special case: Selected Agency allows BSMD to edit their fields
|
||||
if (this.comboBoxAgency.SelectedIndex >= 0)
|
||||
{
|
||||
@ -386,6 +405,7 @@ namespace BreCalClient
|
||||
this.datePickerETD.IsEnabled = isAgency || isBsmd;
|
||||
|
||||
this.labelBSMDGranted.Visibility = editRightGrantedForBSMD ? Visibility.Visible : Visibility.Hidden;
|
||||
this.comboBoxHarbour.IsEnabled = this.IsCreate && this.ShipcallModel.AllowPortChange;
|
||||
|
||||
this.comboBoxCategories_SelectionChanged(null, null);
|
||||
}
|
||||
@ -412,7 +432,7 @@ namespace BreCalClient
|
||||
private void comboBoxDepartureBerth_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
this.CheckForCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
private void buttonEditShips_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@ -420,7 +440,7 @@ namespace BreCalClient
|
||||
{
|
||||
ShipApi = this.ShipApi
|
||||
};
|
||||
|
||||
|
||||
shipListDialog.ShowDialog();
|
||||
|
||||
// reload combobox
|
||||
@ -428,6 +448,24 @@ namespace BreCalClient
|
||||
this.comboBoxShip.ItemsSource = BreCalLists.Ships;
|
||||
}
|
||||
|
||||
private void comboBoxHarbour_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
Port port = (Port)this.comboBoxHarbour.SelectedItem;
|
||||
if (port == null) return;
|
||||
|
||||
// Filter berth selection combobox by port
|
||||
List<Berth> availableBerths = BreCalLists.GetBerthsByPort(port.Id);
|
||||
this.comboBoxArrivalBerth.ItemsSource = null;
|
||||
this.comboBoxArrivalBerth.ItemsSource = availableBerths;
|
||||
this.comboBoxDepartureBerth.ItemsSource = null;
|
||||
this.comboBoxDepartureBerth.ItemsSource = availableBerths;
|
||||
|
||||
// Filter agency combobox by port
|
||||
List<Participant> availableAgencies = BreCalLists.GetParticipants(port.Id, ParticipantType.AGENCY);
|
||||
this.comboBoxAgency.ItemsSource = null;
|
||||
this.comboBoxAgency.ItemsSource = availableAgencies;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Copyright (c) 2023 schick Informatik
|
||||
// Description: Input control for incoming shipcalls
|
||||
//
|
||||
//
|
||||
|
||||
using BreCalClient.misc.Model;
|
||||
using System;
|
||||
@ -33,7 +33,7 @@ namespace BreCalClient
|
||||
|
||||
public ShipcallControlModel ShipcallModel { get; set; } = new();
|
||||
|
||||
public Times Times { get; set; } = new();
|
||||
public Times Times { get; set; } = new();
|
||||
|
||||
#endregion
|
||||
|
||||
@ -41,19 +41,27 @@ namespace BreCalClient
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
|
||||
this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
|
||||
this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
|
||||
this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
|
||||
|
||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
|
||||
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||
{
|
||||
int portId = this.ShipcallModel.Shipcall.PortId;
|
||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.GetBerthsByPort(portId);
|
||||
this.comboBoxMooring.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.MOORING);
|
||||
this.comboBoxPilot.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.PILOT);
|
||||
this.comboBoxTug.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TUG);
|
||||
this.comboBoxTerminal.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TERMINAL);
|
||||
}
|
||||
|
||||
this.CopyToControls();
|
||||
|
||||
this.Title = this.ShipcallModel.Title;
|
||||
|
||||
this.Title = this.ShipcallModel?.Title;
|
||||
|
||||
Participant? p = null;
|
||||
if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||
if (this.ShipcallModel != null)
|
||||
{
|
||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||
}
|
||||
|
||||
bool allowBSMD = false;
|
||||
if (p != null)
|
||||
@ -65,7 +73,7 @@ namespace BreCalClient
|
||||
(App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
|
||||
|
||||
this.EnableControls();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void buttonOK_Click(object sender, RoutedEventArgs e)
|
||||
@ -93,7 +101,7 @@ namespace BreCalClient
|
||||
#region private methods
|
||||
|
||||
private bool CheckValues(out string message)
|
||||
{
|
||||
{
|
||||
message = "";
|
||||
|
||||
if ((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd)) // something has changed
|
||||
@ -130,7 +138,7 @@ namespace BreCalClient
|
||||
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())
|
||||
{
|
||||
@ -138,7 +146,8 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
||||
if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) ||
|
||||
(this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
||||
{
|
||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||
return false;
|
||||
@ -153,7 +162,7 @@ namespace BreCalClient
|
||||
{
|
||||
this.Times.EtaBerth = this.datePickerETA.Value;
|
||||
this.Times.EtaIntervalEnd = this.datePickerETA_End.Value;
|
||||
|
||||
|
||||
if (this.comboBoxPierside.SelectedIndex >= 0)
|
||||
{
|
||||
this.ShipcallModel.Shipcall.PierSide = (this.comboBoxPierside.SelectedIndex == 0);
|
||||
@ -163,8 +172,8 @@ namespace BreCalClient
|
||||
this.ShipcallModel.Shipcall.PierSide = null;
|
||||
}
|
||||
|
||||
this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
|
||||
this.Times.BerthId = (int?)this.comboBoxArrivalBerth.SelectedValue;
|
||||
this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
|
||||
this.Times.BerthId = (int?)this.comboBoxArrivalBerth.SelectedValue;
|
||||
|
||||
this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
|
||||
this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
|
||||
@ -172,9 +181,9 @@ namespace BreCalClient
|
||||
this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
|
||||
|
||||
this.ShipcallModel.Shipcall.Anchored = this.checkBoxAnchored.IsChecked;
|
||||
|
||||
|
||||
this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
|
||||
|
||||
|
||||
this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
|
||||
this.ShipcallModel.Shipcall.Bunkering = this.checkBoxBunkering.IsChecked;
|
||||
this.ShipcallModel.Shipcall.ReplenishingTerminal = this.checkBoxReplenishingTerminal.IsChecked;
|
||||
@ -186,7 +195,7 @@ namespace BreCalClient
|
||||
Participant? participant = (Participant?)this.comboBoxMooring.SelectedItem;
|
||||
if (participant != null)
|
||||
{
|
||||
ParticipantAssignment participantAssignment = new() {
|
||||
ParticipantAssignment participantAssignment = new() {
|
||||
ParticipantId = participant.Id,
|
||||
Type = (int)Extensions.ParticipantType.MOORING
|
||||
};
|
||||
@ -234,14 +243,14 @@ namespace BreCalClient
|
||||
if(this.Times.EtaBerth.HasValue)
|
||||
{
|
||||
this.datePickerETA.Value = this.Times.EtaBerth.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if not set through times use value of BSMD entry
|
||||
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
|
||||
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
||||
}
|
||||
|
||||
|
||||
this.datePickerETA_End.Value = this.Times.EtaIntervalEnd;
|
||||
|
||||
if (Times.BerthId.HasValue)
|
||||
@ -261,12 +270,12 @@ namespace BreCalClient
|
||||
this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
||||
|
||||
this.checkBoxAnchored.IsChecked = this.ShipcallModel.Shipcall.Anchored ?? false;
|
||||
|
||||
|
||||
this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
|
||||
|
||||
|
||||
|
||||
|
||||
this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
|
||||
|
||||
|
||||
this.checkBoxBunkering.IsChecked = this.ShipcallModel.Shipcall.Bunkering ?? false;
|
||||
this.checkBoxReplenishingLock.IsChecked = this.ShipcallModel.Shipcall.ReplenishingLock ?? false;
|
||||
this.checkBoxReplenishingTerminal.IsChecked = this.ShipcallModel.Shipcall.ReplenishingTerminal ?? false;
|
||||
@ -276,7 +285,7 @@ namespace BreCalClient
|
||||
else
|
||||
this.labelETA.Content = string.Format("ETA {0}", BreCalLists.TimeRefs[this.ShipcallModel.Shipcall.TimeRefPoint ?? 0]);
|
||||
|
||||
if(!string.IsNullOrEmpty(this.Times.Remarks))
|
||||
if(!string.IsNullOrEmpty(this.Times.Remarks))
|
||||
this.textBoxRemarks.Text = this.Times.Remarks;
|
||||
|
||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.MOORING))
|
||||
@ -309,8 +318,8 @@ namespace BreCalClient
|
||||
{
|
||||
this.comboBoxTug.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,10 +336,10 @@ namespace BreCalClient
|
||||
this.checkBoxCanceled.IsEnabled = _editing;
|
||||
|
||||
this.checkBoxAnchored.IsEnabled = _editing;
|
||||
|
||||
|
||||
this.comboBoxTug.IsEnabled = _editing;
|
||||
this.integerUpDownRecommendedTugs.IsEnabled = _editing;
|
||||
|
||||
|
||||
this.comboBoxPilot.IsEnabled = _editing;
|
||||
this.comboBoxMooring.IsEnabled = _editing;
|
||||
this.checkBoxMooredLock.IsEnabled = _editing;
|
||||
@ -357,7 +366,7 @@ namespace BreCalClient
|
||||
|
||||
private void CheckOKButton()
|
||||
{
|
||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet();
|
||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet() && !(this.ShipcallModel.Shipcall?.Canceled ?? false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -392,17 +401,17 @@ namespace BreCalClient
|
||||
{
|
||||
this.comboBoxTerminal.SelectedIndex = -1;
|
||||
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void contextMenuItemClearPierside_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxPierside.SelectedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void doubleUpDownDraft_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||
{
|
||||
this.CheckOKButton();
|
||||
}
|
||||
}
|
||||
|
||||
private void datePickerETA_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||
{
|
||||
@ -412,7 +421,7 @@ namespace BreCalClient
|
||||
private void comboBoxArrivalBerth_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
this.CheckOKButton();
|
||||
}
|
||||
}
|
||||
|
||||
private void datePickerETA_End_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Copyright (c) 2023 schick Informatik
|
||||
// Description: Input control for outgoing shipcalls
|
||||
//
|
||||
//
|
||||
|
||||
using BreCalClient.misc.Model;
|
||||
using System;
|
||||
@ -34,7 +34,7 @@ namespace BreCalClient
|
||||
|
||||
public ShipcallControlModel ShipcallModel { get; set; } = new();
|
||||
|
||||
public Times Times { get; set; } = new();
|
||||
public Times Times { get; set; } = new();
|
||||
|
||||
#endregion
|
||||
|
||||
@ -42,20 +42,27 @@ namespace BreCalClient
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
|
||||
this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
|
||||
this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
|
||||
this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
|
||||
|
||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
|
||||
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||
{
|
||||
int portId = this.ShipcallModel.Shipcall.PortId;
|
||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.GetBerthsByPort(portId);
|
||||
this.comboBoxMooring.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.MOORING);
|
||||
this.comboBoxPilot.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.PILOT);
|
||||
this.comboBoxTug.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TUG);
|
||||
this.comboBoxTerminal.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TERMINAL);
|
||||
}
|
||||
|
||||
this.CopyToControls();
|
||||
|
||||
this.Title = this.ShipcallModel.Title;
|
||||
this.Title = this.ShipcallModel?.Title;
|
||||
|
||||
Participant? p = null;
|
||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||
|
||||
if (this.ShipcallModel != null)
|
||||
{
|
||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||
}
|
||||
bool allowBSMD = false;
|
||||
if (p != null)
|
||||
{
|
||||
@ -66,10 +73,10 @@ namespace BreCalClient
|
||||
(App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
|
||||
|
||||
this.EnableControls();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void buttonOK_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@ -107,7 +114,7 @@ namespace BreCalClient
|
||||
message = BreCalClient.Resources.Resources.textETDInThePast;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
|
||||
{
|
||||
@ -122,7 +129,7 @@ namespace BreCalClient
|
||||
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
|
||||
{
|
||||
@ -142,7 +149,8 @@ namespace BreCalClient
|
||||
return false;
|
||||
}
|
||||
|
||||
if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
||||
if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) ||
|
||||
(this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
|
||||
{
|
||||
message = BreCalClient.Resources.Resources.textStartTimeMissing;
|
||||
return false;
|
||||
@ -168,16 +176,16 @@ namespace BreCalClient
|
||||
}
|
||||
|
||||
this.Times.BerthId = (int?)this.comboBoxDepartureBerth.SelectedValue;
|
||||
|
||||
|
||||
this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
|
||||
this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
|
||||
this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
|
||||
this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
|
||||
this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
|
||||
|
||||
|
||||
|
||||
|
||||
this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
|
||||
|
||||
|
||||
this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
|
||||
this.ShipcallModel.Shipcall.RainSensitiveCargo = this.checkBoxRainsensitiveCargo.IsChecked;
|
||||
if(!string.IsNullOrEmpty(this.textBoxRemarks.Text.Trim()))
|
||||
@ -241,7 +249,7 @@ namespace BreCalClient
|
||||
if (this.ShipcallModel.Shipcall.Etd != DateTime.MinValue)
|
||||
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
|
||||
}
|
||||
|
||||
|
||||
this.datePickerETD_End.Value = this.Times.EtdIntervalEnd;
|
||||
|
||||
if (this.Times.BerthId.HasValue)
|
||||
@ -259,10 +267,10 @@ namespace BreCalClient
|
||||
this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
|
||||
this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
|
||||
this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
||||
|
||||
|
||||
|
||||
|
||||
this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
|
||||
|
||||
|
||||
|
||||
this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
|
||||
this.checkBoxRainsensitiveCargo.IsChecked = this.ShipcallModel.Shipcall.RainSensitiveCargo ?? false;
|
||||
@ -270,7 +278,7 @@ namespace BreCalClient
|
||||
if ((this.ShipcallModel.Shipcall.TimeRefPoint ?? 0) == 0)
|
||||
this.labelETD.Content = BreCalClient.Resources.Resources.textETDBerth;
|
||||
else
|
||||
this.labelETD.Content = string.Format("ETD {0}", BreCalLists.TimeRefs[this.ShipcallModel.Shipcall.TimeRefPoint ?? 0]);
|
||||
this.labelETD.Content = string.Format("ETD {0}", BreCalLists.TimeRefs[this.ShipcallModel.Shipcall.TimeRefPoint ?? 0]);
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Times.Remarks))
|
||||
this.textBoxRemarks.Text = this.Times.Remarks;
|
||||
@ -321,9 +329,9 @@ namespace BreCalClient
|
||||
this.datePickerTidalWindowTo.IsEnabled = _editing;
|
||||
this.checkBoxCanceled.IsEnabled = _editing;
|
||||
|
||||
|
||||
|
||||
this.comboBoxTug.IsEnabled = _editing;
|
||||
this.integerUpDownRecommendedTugs.IsEnabled = _editing;
|
||||
this.integerUpDownRecommendedTugs.IsEnabled = _editing;
|
||||
this.comboBoxPilot.IsEnabled = _editing;
|
||||
this.comboBoxMooring.IsEnabled = _editing;
|
||||
this.checkBoxMooredLock.IsEnabled = _editing;
|
||||
@ -348,7 +356,7 @@ namespace BreCalClient
|
||||
|
||||
private void CheckOKButton()
|
||||
{
|
||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet();
|
||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet() && !(this.ShipcallModel.Shipcall?.Canceled ?? false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -383,12 +391,12 @@ namespace BreCalClient
|
||||
{
|
||||
this.comboBoxTerminal.SelectedIndex = -1;
|
||||
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void contextMenuItemClearPierside_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxPierside.SelectedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void datePickerETD_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||
{
|
||||
@ -405,7 +413,7 @@ namespace BreCalClient
|
||||
CheckOKButton();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
using BreCalClient.misc.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Documents;
|
||||
using static BreCalClient.Extensions;
|
||||
|
||||
namespace BreCalClient
|
||||
@ -40,21 +42,30 @@ namespace BreCalClient
|
||||
#region event handler
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
|
||||
this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
|
||||
this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
|
||||
this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
|
||||
{
|
||||
|
||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
|
||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
|
||||
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||
{
|
||||
int portId = this.ShipcallModel.Shipcall.PortId;
|
||||
List<Berth> availableBerths = BreCalLists.GetBerthsByPort(portId);
|
||||
this.comboBoxArrivalBerth.ItemsSource = availableBerths;
|
||||
this.comboBoxDepartureBerth.ItemsSource = availableBerths;
|
||||
this.comboBoxMooring.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.MOORING);
|
||||
this.comboBoxPilot.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.PILOT);
|
||||
this.comboBoxTug.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TUG);
|
||||
this.comboBoxTerminal.ItemsSource = BreCalLists.GetParticipants(portId, ParticipantType.TERMINAL);
|
||||
}
|
||||
|
||||
this.CopyToControls();
|
||||
|
||||
this.Title = this.ShipcallModel.Title;
|
||||
|
||||
Participant? p = null;
|
||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||
|
||||
if (this.ShipcallModel != null)
|
||||
{
|
||||
this.Title = this.ShipcallModel.Title;
|
||||
if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
|
||||
}
|
||||
|
||||
bool allowBSMD = false;
|
||||
if (p != null)
|
||||
@ -383,7 +394,7 @@ namespace BreCalClient
|
||||
|
||||
private void CheckOKButton()
|
||||
{
|
||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet();
|
||||
this.buttonOK.IsEnabled = _editing && RequiredFieldsSet() && !(this.ShipcallModel.Shipcall?.Canceled ?? false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -48,7 +48,7 @@ namespace BreCalClient
|
||||
{
|
||||
if (!CheckValues(out string message))
|
||||
{
|
||||
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning,
|
||||
System.Windows.MessageBox.Show(message, BreCalClient.Resources.Resources.textWarning,
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
else
|
||||
@ -173,13 +173,13 @@ namespace BreCalClient
|
||||
{
|
||||
this.textBoxRemarks.Text = this.Times.Remarks;
|
||||
this.datePickerETABerth.Value = this.Times.EtaBerth;
|
||||
if(this.datePickerETABerth.IsEnabled && (this.Times.EtaBerth == null) && (this.AgencyTimes?.EtaBerth != null) && (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival) && (this.AgencyTimes?.EtaBerth > DateTime.Now))
|
||||
if(this.datePickerETABerth.IsEnabled && (this.Times.EtaBerth == null) && (this.AgencyTimes?.EtaBerth != null) && (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival) && (this.AgencyTimes?.EtaBerth > DateTime.Now.AddDays(-1)))
|
||||
{
|
||||
this.datePickerETABerth.Value = this.AgencyTimes.EtaBerth;
|
||||
if (this.datePickerETABerth.Template.FindName("PART_TextBox", this.datePickerETABerth) is WatermarkTextBox tb) { tb.Focus(); tb.SelectAll(); }
|
||||
}
|
||||
this.datePickerETDBerth.Value = this.Times.EtdBerth;
|
||||
if(this.datePickerETDBerth.IsEnabled && (this.Times.EtdBerth == null) && (this.AgencyTimes?.EtdBerth != null) && ((ShipcallModel.Shipcall?.Type == ShipcallType.Departure) || (ShipcallModel.Shipcall?.Type == ShipcallType.Shifting)) && (this.AgencyTimes?.EtdBerth > DateTime.Now))
|
||||
if(this.datePickerETDBerth.IsEnabled && (this.Times.EtdBerth == null) && (this.AgencyTimes?.EtdBerth != null) && ((ShipcallModel.Shipcall?.Type == ShipcallType.Departure) || (ShipcallModel.Shipcall?.Type == ShipcallType.Shifting)) && (this.AgencyTimes?.EtdBerth > DateTime.Now.AddDays(-1)))
|
||||
{
|
||||
this.datePickerETDBerth.Value = this.AgencyTimes.EtdBerth;
|
||||
if (this.datePickerETDBerth.Template.FindName("PART_TextBox", this.datePickerETDBerth) is WatermarkTextBox tb) tb.SelectAll();
|
||||
@ -190,14 +190,14 @@ namespace BreCalClient
|
||||
this.datePickerATA.Value = this.Times.Ata;
|
||||
this.datePickerATD.Value = this.Times.Atd;
|
||||
this.datePickerETABerth_End.Value = this.Times.EtaIntervalEnd;
|
||||
if (this.datePickerETABerth_End.IsEnabled && (this.Times.EtaIntervalEnd == null) && (this.Times.EtaBerth == null) && (this.AgencyTimes?.EtaIntervalEnd != null) && (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival))
|
||||
if (this.datePickerETABerth_End.IsEnabled && (this.Times.EtaIntervalEnd == null) && (this.Times.EtaBerth == null) && (this.AgencyTimes?.EtaIntervalEnd != null) && (ShipcallModel.Shipcall?.Type == ShipcallType.Arrival) && (this.AgencyTimes?.EtaBerth > DateTime.Now.AddDays(-1)))
|
||||
{
|
||||
this.datePickerETABerth_End.Value = this.AgencyTimes.EtaIntervalEnd;
|
||||
//if (this.datePickerETABerth_End.Template.FindName("PART_TextBox", this.datePickerETABerth_End) is WatermarkTextBox tb) { tb.Focus(); tb.SelectAll(); }
|
||||
}
|
||||
|
||||
this.datePickerETDBerth_End.Value = this.Times.EtdIntervalEnd;
|
||||
if (this.datePickerETDBerth_End.IsEnabled && (this.Times.EtdIntervalEnd == null) && (this.Times.EtdBerth == null) && (this.AgencyTimes?.EtdIntervalEnd != null) && ((ShipcallModel.Shipcall?.Type == ShipcallType.Departure) || (ShipcallModel.Shipcall?.Type == ShipcallType.Shifting)))
|
||||
if (this.datePickerETDBerth_End.IsEnabled && (this.Times.EtdIntervalEnd == null) && (this.Times.EtdBerth == null) && (this.AgencyTimes?.EtdIntervalEnd != null) && ((ShipcallModel.Shipcall?.Type == ShipcallType.Departure) || (ShipcallModel.Shipcall?.Type == ShipcallType.Shifting)) && (this.AgencyTimes?.EtdBerth > DateTime.Now.AddDays(-1)))
|
||||
{
|
||||
this.datePickerETDBerth_End.Value = this.AgencyTimes.EtdIntervalEnd;
|
||||
//if (this.datePickerETDBerth_End.Template.FindName("PART_TextBox", this.datePickerETDBerth_End) is WatermarkTextBox tb) { tb.Focus(); tb.SelectAll(); }
|
||||
@ -259,7 +259,7 @@ namespace BreCalClient
|
||||
|
||||
// setting en/dis-abled
|
||||
|
||||
if (this.Times.ParticipantId != App.Participant.Id)
|
||||
if ((this.Times.ParticipantId != App.Participant.Id) || (this.ShipcallModel.Shipcall?.Canceled ?? false))
|
||||
{
|
||||
this.buttonFixedOrder.IsEnabled = false;
|
||||
this.buttonOK.IsEnabled = false;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Copyright (c) 2023 schick Informatik
|
||||
// Description: Terminals have all different fields so a different dialog
|
||||
//
|
||||
//
|
||||
|
||||
using BreCalClient.misc.Model;
|
||||
using System;
|
||||
@ -30,7 +30,10 @@ namespace BreCalClient
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxBerth.ItemsSource = BreCalLists.Berths;
|
||||
if ((this.ShipcallModel != null) && (this.ShipcallModel.Shipcall != null))
|
||||
this.comboBoxBerth.ItemsSource = BreCalLists.GetBerthsByPort(this.ShipcallModel.Shipcall.PortId);
|
||||
else
|
||||
this.comboBoxBerth.ItemsSource = BreCalLists.Berths;
|
||||
this.CopyToControls();
|
||||
this.EnableControls();
|
||||
}
|
||||
@ -115,7 +118,7 @@ namespace BreCalClient
|
||||
message = BreCalClient.Resources.Resources.textOperationStartInThePast;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.datePickerOperationStart.Value.HasValue && this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart.Value > this.datePickerOperationStart_End.Value)
|
||||
{
|
||||
@ -130,7 +133,7 @@ namespace BreCalClient
|
||||
message = BreCalClient.Resources.Resources.textOperationEndInThePast;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.datePickerOperationEnd.Value.HasValue && this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd.Value > this.datePickerOperationEnd_End.Value)
|
||||
{
|
||||
@ -187,7 +190,7 @@ namespace BreCalClient
|
||||
case ShipcallType.Arrival:
|
||||
this.labelEnd.Visibility = Visibility.Hidden;
|
||||
this.datePickerOperationEnd.Visibility = Visibility.Hidden;
|
||||
this.datePickerOperationEnd_End.Visibility = Visibility.Hidden;
|
||||
this.datePickerOperationEnd_End.Visibility = Visibility.Hidden;
|
||||
this.rowEnd.Height = new(0);
|
||||
break;
|
||||
case ShipcallType.Departure:
|
||||
@ -200,7 +203,7 @@ namespace BreCalClient
|
||||
this.textBoxBerthRemarks.Visibility = Visibility.Hidden;
|
||||
break;
|
||||
case ShipcallType.Shifting:
|
||||
this.rowStart.Height = new(0);
|
||||
this.rowStart.Height = new(0);
|
||||
this.labelBerth.Visibility = Visibility.Hidden;
|
||||
this.comboBoxBerth.Visibility = Visibility.Hidden;
|
||||
this.labelPierside.Visibility = Visibility.Hidden;
|
||||
@ -214,7 +217,7 @@ namespace BreCalClient
|
||||
|
||||
private void EnableControls()
|
||||
{
|
||||
if (this.Times.ParticipantId != App.Participant.Id)
|
||||
if ((this.Times.ParticipantId != App.Participant.Id) || (this.ShipcallModel.Shipcall?.Canceled ?? false))
|
||||
{
|
||||
this.buttonOK.IsEnabled = false;
|
||||
return;
|
||||
@ -229,10 +232,10 @@ namespace BreCalClient
|
||||
this.textBoxBerthRemarks.IsReadOnly = ShipcallModel.Shipcall?.Type != ShipcallType.Arrival;
|
||||
this.textBoxRemarks.IsReadOnly = false;
|
||||
this.buttonClearAll.IsEnabled = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,9 +73,19 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Margin="2" Grid.Column="0" Content="{x:Static p:Resources.textNewDots}" x:Name="buttonNew" Visibility="Hidden" Click="buttonNew_Click" Background="Transparent"/>
|
||||
<Label Content="{x:Static p:Resources.textSortOrder}" Grid.Column="1" HorizontalContentAlignment="Right"/>
|
||||
<ComboBox x:Name="comboBoxSortOrder" Margin="2" Grid.Column="2" SelectionChanged="comboBoxSortOrder_SelectionChanged" />
|
||||
<CheckBox x:Name="checkboxShowCancelledCalls" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Checked="checkboxShowCancelledCalls_Checked" Unchecked="checkboxShowCancelledCalls_Checked" />
|
||||
<Label Content="{x:Static p:Resources.textShowCancelledShipcalls}" Grid.Column="4" />
|
||||
<Grid Grid.Column="2" Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width=".5*" />
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width=".5*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ComboBox x:Name="comboBoxSortOrder" Margin="2" Grid.Column="0" SelectionChanged="comboBoxSortOrder_SelectionChanged" />
|
||||
<CheckBox x:Name="checkboxShowCancelledCalls" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Checked="checkboxShowCancelledCalls_Checked" Unchecked="checkboxShowCancelledCalls_Checked" />
|
||||
<Label Content="{x:Static p:Resources.textShowCancelledShipcalls}" Grid.Column="2" />
|
||||
</Grid>
|
||||
<Label Content="{x:Static p:Resources.textHarbour}" Grid.Column="3" HorizontalAlignment="Right" />
|
||||
<xctk:CheckComboBox x:Name="comboBoxPorts" Margin="2" Grid.Column="4" ItemSelectionChanged="comboBoxPorts_ItemSelectionChanged" DisplayMemberPath="Name" />
|
||||
|
||||
<Button Margin="2" Grid.Column="6" Content="{x:Static p:Resources.textClearFilters}" x:Name="buttonClearFilter" Click="buttonClearFilter_Click" Background="Transparent" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="2">
|
||||
|
||||
@ -25,6 +25,7 @@ using System.Net;
|
||||
using System.Windows.Input;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace BreCalClient
|
||||
@ -167,15 +168,25 @@ namespace BreCalClient
|
||||
{
|
||||
if (_loginResult.Id > 0)
|
||||
{
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
this.busyIndicator.IsBusy = false;
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
this._userApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._shipcallApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._timesApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._staticApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._shipApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this.LoadStaticLists();
|
||||
this.labelUsername.Text = $"{_loginResult.FirstName} {_loginResult.LastName}";
|
||||
bool loadingSuccessful = await this.LoadStaticLists();
|
||||
if (loadingSuccessful)
|
||||
{
|
||||
this.labelUsername.Text = $"{_loginResult.FirstName} {_loginResult.LastName}";
|
||||
this.busyIndicator.IsBusy = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Mouse.OverrideCursor = null;
|
||||
textUsername.Text = "";
|
||||
textPassword.Password = "";
|
||||
textUsername.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
labelGeneralStatus.Text = $"Connection {ConnectionStatus.SUCCESSFUL}";
|
||||
@ -184,10 +195,10 @@ namespace BreCalClient
|
||||
{
|
||||
if ((ex.ErrorContent != null && ((string)ex.ErrorContent).StartsWith("{"))) {
|
||||
Error? anError = JsonConvert.DeserializeObject<Error>((string)ex.ErrorContent);
|
||||
if ((anError != null) && anError.Message.Equals("invalid credentials"))
|
||||
if ((anError != null) && anError.ErrorField.Equals("invalid credentials"))
|
||||
this.labelLoginResult.Content = BreCalClient.Resources.Resources.textWrongCredentials;
|
||||
else
|
||||
this.labelLoginResult.Content = anError?.Message ?? ex.Message;
|
||||
this.labelLoginResult.Content = anError?.ErrorField ?? ex.Message;
|
||||
}
|
||||
else {
|
||||
this.labelLoginResult.Content = ex.Message;
|
||||
@ -246,7 +257,8 @@ namespace BreCalClient
|
||||
EditShipcallControl esc = new()
|
||||
{
|
||||
ShipEditingEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD),
|
||||
ShipApi = _shipApi
|
||||
ShipApi = _shipApi,
|
||||
IsCreate = true
|
||||
};
|
||||
if (model != null)
|
||||
esc.ShipcallModel = model;
|
||||
@ -287,7 +299,9 @@ namespace BreCalClient
|
||||
}
|
||||
};
|
||||
scmOut.Shipcall.ShipId = esc.ShipcallModel.Shipcall.ShipId;
|
||||
scmOut.Shipcall.PortId = esc.ShipcallModel.Shipcall.PortId;
|
||||
scmOut.Ship = esc.ShipcallModel.Ship;
|
||||
scmOut.AllowPortChange = false;
|
||||
DateTime eta = esc.ShipcallModel.Shipcall?.Eta ?? DateTime.Now;
|
||||
scmOut.Shipcall.Etd = eta.AddDays(2);
|
||||
scmOut.Shipcall.DepartureBerthId = esc.ShipcallModel.Shipcall?.ArrivalBerthId;
|
||||
@ -337,7 +351,7 @@ namespace BreCalClient
|
||||
{
|
||||
this.Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
ShowErrorDialog(ex.Message, "Error saving user information");
|
||||
ShowErrorDialog(ex.Message, "Error saving user information");
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -349,6 +363,7 @@ namespace BreCalClient
|
||||
{
|
||||
this.searchFilterControl.ClearFilters();
|
||||
this.checkboxShowCancelledCalls.IsChecked = false;
|
||||
this.comboBoxPorts.UnSelectAll();
|
||||
this.FilterShipcalls();
|
||||
}
|
||||
|
||||
@ -366,6 +381,24 @@ namespace BreCalClient
|
||||
this.SearchFilterControl_SearchFilterChanged();
|
||||
}
|
||||
|
||||
private void comboBoxPorts_ItemSelectionChanged(object sender, Xceed.Wpf.Toolkit.Primitives.ItemSelectionChangedEventArgs e)
|
||||
{
|
||||
this.searchFilterControl.SearchFilter.Ports.Clear();
|
||||
|
||||
List<Berth> berths = new List<Berth>();
|
||||
foreach (Port port in comboBoxPorts.SelectedItems)
|
||||
{
|
||||
this.searchFilterControl.SearchFilter.Ports.Add(port.Id);
|
||||
berths.AddRange(BreCalLists.GetBerthsByPort(port.Id));
|
||||
}
|
||||
// create list of berths from selected port(s) or return all berths
|
||||
if (berths.Count == 0)
|
||||
berths = BreCalLists.AllBerths;
|
||||
this.searchFilterControl.SetBerths(berths);
|
||||
|
||||
this.SearchFilterControl_SearchFilterChanged();
|
||||
}
|
||||
|
||||
private async void comboBoxSortOrder_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
_sortOrder = (Extensions.SortOrder) this.comboBoxSortOrder.SelectedIndex;
|
||||
@ -405,14 +438,22 @@ namespace BreCalClient
|
||||
|
||||
#region network operations
|
||||
|
||||
private async void LoadStaticLists()
|
||||
private async Task<bool> LoadStaticLists()
|
||||
{
|
||||
if (_loginResult == null) return;
|
||||
if (_loginResult == null) return false;
|
||||
|
||||
BreCalLists.InitializePorts(await _staticApi.GetPortsAsync());
|
||||
BreCalLists.InitializeBerths(await _staticApi.BerthsGetAsync());
|
||||
BreCalLists.InitializeShips(await _shipApi.ShipsGetAsync());
|
||||
BreCalLists.InitializeParticipants(await _staticApi.ParticipantsGetAsync());
|
||||
|
||||
if(BreCalLists.Participants.Count == 0)
|
||||
{
|
||||
MessageBox.Show(BreCalClient.Resources.Resources.textNoPortAssigned, BreCalClient.Resources.Resources.textError, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.searchFilterControl.SetBerths(BreCalLists.Berths);
|
||||
|
||||
foreach (Participant participant in BreCalLists.Participants)
|
||||
@ -448,18 +489,27 @@ namespace BreCalClient
|
||||
SearchFilterModel.filterMap[_loginResult.Id] = currentFilter;
|
||||
}
|
||||
this.searchFilterControl.SetFilterFromModel(currentFilter);
|
||||
|
||||
if ((currentFilter.Ports != null) && (this.comboBoxPorts.ItemsSource != null))
|
||||
{
|
||||
foreach (Port p in this.comboBoxPorts.ItemsSource)
|
||||
{
|
||||
if (currentFilter.Ports.Contains(p.Id)) this.comboBoxPorts.SelectedItems.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ = Task.Run(() => RefreshShipcalls());
|
||||
_ = Task.Run(() => RefreshShips());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public async Task RefreshShips()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
Thread.Sleep(SHIPS_UPDATE_INTERVAL_SECONDS * 1000);
|
||||
BreCalLists.InitializeShips(await _shipApi.ShipsGetAsync());
|
||||
}
|
||||
@ -604,7 +654,7 @@ namespace BreCalClient
|
||||
{
|
||||
ShipcallControl sc = new()
|
||||
{
|
||||
Height = 135,
|
||||
Height = 145,
|
||||
ShipcallControlModel = scm
|
||||
};
|
||||
sc.EditTimesRequested += Sc_EditTimesRequested;
|
||||
@ -674,7 +724,7 @@ namespace BreCalClient
|
||||
// first add everything
|
||||
this._visibleControlModels.AddRange(_allShipcallsDict.Values);
|
||||
|
||||
// now remove elements whose filter criteria are met
|
||||
// now remove elements whose filter criteria are met
|
||||
|
||||
if(sfm.Berths.Count > 0 )
|
||||
{
|
||||
@ -700,6 +750,11 @@ namespace BreCalClient
|
||||
_ = this._visibleControlModels.RemoveAll(x => { if (x.Shipcall == null) return false; else return !sfm.Categories.Contains(x.Shipcall.Type); });
|
||||
}
|
||||
|
||||
if(sfm.Ports.Count > 0 )
|
||||
{
|
||||
_ = this._visibleControlModels.RemoveAll(x => { if(x.Shipcall == null) return false; else return !sfm.Ports.Contains(x.Shipcall.PortId); });
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(sfm.SearchString))
|
||||
{
|
||||
_ = this._visibleControlModels.RemoveAll(x => !(x.ContainsRemarkText(sfm.SearchString) || (x.Ship?.Name.Contains(sfm.SearchString, StringComparison.InvariantCultureIgnoreCase) ?? false)));
|
||||
@ -1085,30 +1140,32 @@ namespace BreCalClient
|
||||
if (msg.error_field != null)
|
||||
{
|
||||
caption = $"{caption}: {msg.error_field}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(msg.error_description != null)
|
||||
{
|
||||
message = msg.error_description;
|
||||
}
|
||||
message = msg.error_description;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
}
|
||||
|
||||
_log.ErrorFormat("{0} - {1}", caption, message);
|
||||
|
||||
|
||||
Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
MessageBox.Show(message, caption, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void EnableControlsForParticipant()
|
||||
{
|
||||
if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD))
|
||||
this.buttonNew.Visibility = Visibility.Visible;
|
||||
|
||||
this.comboBoxPorts.ItemsSource = BreCalLists.AllPorts.Where(x => App.Participant.Ports.Contains(x.Id));
|
||||
}
|
||||
|
||||
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
||||
|
||||
@ -4,8 +4,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ApplicationRevision>1</ApplicationRevision>
|
||||
<ApplicationVersion>1.4.1.0</ApplicationVersion>
|
||||
<ApplicationRevision>2</ApplicationRevision>
|
||||
<ApplicationVersion>1.6.0.4</ApplicationVersion>
|
||||
<BootstrapperEnabled>True</BootstrapperEnabled>
|
||||
<Configuration>Debug</Configuration>
|
||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||
@ -36,8 +36,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UpdateEnabled>True</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateRequired>False</UpdateRequired>
|
||||
<UpdateRequired>True</UpdateRequired>
|
||||
<WebPageFileName>Publish.html</WebPageFileName>
|
||||
<MinimumRequiredVersion>1.6.0.4</MinimumRequiredVersion>
|
||||
<SkipPublishVerification>false</SkipPublishVerification>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PublishFile Include="containership.ico">
|
||||
|
||||
@ -4,8 +4,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ApplicationRevision>12</ApplicationRevision>
|
||||
<ApplicationVersion>1.5.0.12</ApplicationVersion>
|
||||
<ApplicationRevision>8</ApplicationRevision>
|
||||
<ApplicationVersion>1.6.0.8</ApplicationVersion>
|
||||
<BootstrapperEnabled>False</BootstrapperEnabled>
|
||||
<Configuration>Release</Configuration>
|
||||
<CreateWebPageOnPublish>True</CreateWebPageOnPublish>
|
||||
@ -30,7 +30,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UpdateEnabled>True</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateRequired>False</UpdateRequired>
|
||||
<UpdateRequired>True</UpdateRequired>
|
||||
<WebPageFileName>Publish.html</WebPageFileName>
|
||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||
<ErrorReportUrl>https://www.bsmd-emswe.eu/</ErrorReportUrl>
|
||||
@ -39,6 +39,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<SuiteName>Bremen calling client</SuiteName>
|
||||
<SupportUrl>https://www.bsmd-emswe.eu/</SupportUrl>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SkipPublishVerification>false</SkipPublishVerification>
|
||||
<MinimumRequiredVersion>1.6.0.8</MinimumRequiredVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PublishFile Include="containership.ico">
|
||||
|
||||
@ -4,8 +4,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ApplicationRevision>8</ApplicationRevision>
|
||||
<ApplicationVersion>1.5.0.8</ApplicationVersion>
|
||||
<ApplicationRevision>6</ApplicationRevision>
|
||||
<ApplicationVersion>1.6.0.8</ApplicationVersion>
|
||||
<BootstrapperEnabled>True</BootstrapperEnabled>
|
||||
<Configuration>Debug</Configuration>
|
||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||
@ -30,7 +30,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UpdateEnabled>True</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateRequired>False</UpdateRequired>
|
||||
<UpdateRequired>True</UpdateRequired>
|
||||
<WebPageFileName>Publish.html</WebPageFileName>
|
||||
<CreateDesktopShortcut>True</CreateDesktopShortcut>
|
||||
<ErrorReportUrl>https://www.bsmd-emswe.eu/</ErrorReportUrl>
|
||||
@ -41,6 +41,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<PublishDir>bin\Debug\net6.0-windows\win-x64\app.publish\</PublishDir>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SkipPublishVerification>false</SkipPublishVerification>
|
||||
<MinimumRequiredVersion>1.6.0.8</MinimumRequiredVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PublishFile Include="containership.ico">
|
||||
|
||||
18
src/BreCalClient/Resources/Resources.Designer.cs
generated
18
src/BreCalClient/Resources/Resources.Designer.cs
generated
@ -749,6 +749,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Harbour.
|
||||
/// </summary>
|
||||
public static string textHarbour {
|
||||
get {
|
||||
return ResourceManager.GetString("textHarbour", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Incoming.
|
||||
/// </summary>
|
||||
@ -866,6 +875,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No port assigned to this participant.
|
||||
/// </summary>
|
||||
public static string textNoPortAssigned {
|
||||
get {
|
||||
return ResourceManager.GetString("textNoPortAssigned", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Not rotated.
|
||||
/// </summary>
|
||||
|
||||
@ -286,6 +286,9 @@
|
||||
<data name="textFrom" xml:space="preserve">
|
||||
<value>von</value>
|
||||
</data>
|
||||
<data name="textHarbour" xml:space="preserve">
|
||||
<value>Hafen</value>
|
||||
</data>
|
||||
<data name="textIncoming" xml:space="preserve">
|
||||
<value>Einkommend</value>
|
||||
</data>
|
||||
@ -550,4 +553,7 @@
|
||||
<data name="textStartTimeMissing" xml:space="preserve">
|
||||
<value>Wenn eine Ende-Zeit angegeben wird, muss auch eine Start-Zeit angegeben werden</value>
|
||||
</data>
|
||||
<data name="textNoPortAssigned" xml:space="preserve">
|
||||
<value>Es ist keine Hafenzuordnung vorhanden</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -328,6 +328,9 @@
|
||||
<data name="textFrom" xml:space="preserve">
|
||||
<value>from</value>
|
||||
</data>
|
||||
<data name="textHarbour" xml:space="preserve">
|
||||
<value>Harbour</value>
|
||||
</data>
|
||||
<data name="textIncoming" xml:space="preserve">
|
||||
<value>Incoming</value>
|
||||
</data>
|
||||
@ -598,4 +601,7 @@
|
||||
<data name="textStartTimeMissing" xml:space="preserve">
|
||||
<value>If an end time is set, a start time is also required</value>
|
||||
</data>
|
||||
<data name="textNoPortAssigned" xml:space="preserve">
|
||||
<value>No port assigned to this participant</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -25,6 +25,8 @@ namespace BreCalClient
|
||||
|
||||
public List<int> Berths { get; set; } = new();
|
||||
|
||||
public List<int> Ports { get; set; } = new();
|
||||
|
||||
public string? SearchString { get; set; }
|
||||
|
||||
public double? ShipLengthFrom { get; set; }
|
||||
|
||||
@ -20,12 +20,12 @@
|
||||
<ColumnDefinition Width=".15*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32" />
|
||||
<RowDefinition Height="42" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="42"/>
|
||||
<RowDefinition Height=".125*"/>
|
||||
<RowDefinition Height=".125*"/>
|
||||
<RowDefinition Height=".125*"/>
|
||||
@ -76,39 +76,76 @@
|
||||
<TextBlock x:Name="textBlockLengthWidth" Padding="0"/>
|
||||
</Viewbox>
|
||||
<Viewbox Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{x:Static p:Resources.textDraft}" Padding="0" />
|
||||
</Viewbox>
|
||||
<Viewbox Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left">
|
||||
<TextBlock x:Name="textBlockDraft" Padding="0"/>
|
||||
</Viewbox>
|
||||
<Viewbox Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left">
|
||||
<TextBlock Text="ETA" x:Name="labelETA"/>
|
||||
</Viewbox>
|
||||
<Viewbox Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left">
|
||||
<Viewbox Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left">
|
||||
<TextBlock x:Name="textBlockETA" Padding="0" FontWeight="DemiBold"/>
|
||||
</Viewbox>
|
||||
<Viewbox Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left">
|
||||
<Viewbox Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{x:Static p:Resources.textBerth}"/>
|
||||
</Viewbox>
|
||||
<Viewbox Grid.Row="6" Grid.Column="1" HorizontalAlignment="Left">
|
||||
<Viewbox Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left">
|
||||
<TextBlock x:Name="textBlockBerth" Padding="0" FontWeight="DemiBold" />
|
||||
</Viewbox>
|
||||
|
||||
<Viewbox Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Left">
|
||||
<TextBlock x:Name="textBlockHarbour" Padding="0" FontWeight="DemiBold" />
|
||||
</Viewbox>
|
||||
|
||||
</Grid>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="1" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
<Grid Grid.Row="0" Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="14" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelAgent" PreviewMouseUp="labelAgent_PreviewMouseUp"/>
|
||||
<Label Grid.Row="0" Grid.Column="2" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelMooring" PreviewMouseUp="labelMooring_PreviewMouseUp"/>
|
||||
<Label Grid.Row="0" Grid.Column="3" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPortAuthority" PreviewMouseUp="labelPortAuthority_PreviewMouseUp" />
|
||||
<Label Grid.Row="0" Grid.Column="4" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPilot" PreviewMouseUp="labelPilot_PreviewMouseUp"/>
|
||||
<Label Grid.Row="0" Grid.Column="5" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTug" PreviewMouseUp="labelTug_PreviewMouseUp"/>
|
||||
<Label Grid.Row="0" Grid.Column="6" Grid.RowSpan="1" FontSize="12" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTerminal" PreviewMouseUp="labelTerminal_PreviewMouseUp" />
|
||||
<Label Name="labelLastChangeAgency" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="0" Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="14" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelMooring" PreviewMouseUp="labelMooring_PreviewMouseUp"/>
|
||||
<Label Name="labelLastChangeMooring" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="0" Grid.Column="3">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="14" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPortAuthority" PreviewMouseUp="labelPortAuthority_PreviewMouseUp"/>
|
||||
<Label Name="labelLastChangePortAuthority" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="0" Grid.Column="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="14" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelPilot" PreviewMouseUp="labelPilot_PreviewMouseUp"/>
|
||||
<Label Name="labelLastChangePilot" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="0" Grid.Column="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="14" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTug" PreviewMouseUp="labelTug_PreviewMouseUp"/>
|
||||
<Label Name="labelLastChangeTug" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="0" Grid.Column="6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="14" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Padding="0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" FontSize="13" Content="- / -" Foreground="White" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTerminal" PreviewMouseUp="labelTerminal_PreviewMouseUp"/>
|
||||
<Label Name="labelLastChangeTerminal" FontSize="9" Padding="0" VerticalContentAlignment="Center" Grid.Row="1" Foreground="WhiteSmoke" Background="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" HorizontalContentAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<!-- AGENCY -->
|
||||
<Border Grid.Row="2" Grid.Column="1" BorderThickness="1, 0, 0, 0" BorderBrush="{Binding Source={x:Static sets:Settings.Default}, Path=BG_COLOR}" Padding="3,0,0,0">
|
||||
|
||||
@ -72,7 +72,7 @@ namespace BreCalClient
|
||||
|
||||
string agentName = "";
|
||||
string? name;
|
||||
_agency = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.AGENCY);
|
||||
_agency = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.AGENCY);
|
||||
name = _agency?.Name;
|
||||
if (name != null) agentName = name;
|
||||
this.labelAgent.Content = name ?? "- / -";
|
||||
@ -83,10 +83,9 @@ namespace BreCalClient
|
||||
this.labelAgencyETAETDValue.Content = "";
|
||||
this.textBlockAgencyRemarks.Text = "";
|
||||
this.textBlockAgencyBerthRemarks.Text = "";
|
||||
this.textBlockDraft.Text = "";
|
||||
}
|
||||
|
||||
_mooring = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.MOORING);
|
||||
_mooring = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.MOORING);
|
||||
name = _mooring?.Name;
|
||||
this.labelMooring.Content = name ?? "- / -";
|
||||
if(_mooring == null)
|
||||
@ -95,7 +94,7 @@ namespace BreCalClient
|
||||
this.textBlockMooringRemarks.Text = "";
|
||||
}
|
||||
|
||||
_pilot = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PILOT);
|
||||
_pilot = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.PILOT);
|
||||
name = _pilot?.Name;
|
||||
this.labelPilot.Content = name ?? "- / - ";
|
||||
if(_pilot == null)
|
||||
@ -104,7 +103,7 @@ namespace BreCalClient
|
||||
this.textBlockPilotRemarks.Text = "";
|
||||
}
|
||||
|
||||
_tug = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TUG);
|
||||
_tug = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.TUG);
|
||||
name = _tug?.Name;
|
||||
this.labelTug.Content = name ?? "- / - ";
|
||||
if(_tug == null)
|
||||
@ -113,7 +112,7 @@ namespace BreCalClient
|
||||
this.textBlockTugRemarks.Text = "";
|
||||
}
|
||||
|
||||
_port_administration = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
||||
_port_administration = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
||||
name = _port_administration?.Name;
|
||||
this.labelPortAuthority.Content = name ?? "- / - ";
|
||||
if(_port_administration == null)
|
||||
@ -122,7 +121,7 @@ namespace BreCalClient
|
||||
this.textBlockPortAuthorityRemarks.Text = "";
|
||||
}
|
||||
|
||||
_terminal = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TERMINAL);
|
||||
_terminal = this.ShipcallControlModel?.GetParticipantForType(Extensions.ParticipantType.TERMINAL);
|
||||
name = _terminal?.Name;
|
||||
this.labelTerminal.Content = name ?? "- / - ";
|
||||
if(_terminal == null)
|
||||
@ -269,22 +268,9 @@ namespace BreCalClient
|
||||
else
|
||||
this.imageEvaluation.ToolTip = null;
|
||||
|
||||
//Times? bsmdTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.BSMD);
|
||||
//if (bsmdTimes != null)
|
||||
this.textBlockBerth.Text = this.ShipcallControlModel?.GetBerthText(null);
|
||||
//else
|
||||
// this.textBlockBerth.Text = this.ShipcallControlModel?.Berth;
|
||||
|
||||
this.textBlockBerth.Text = this.ShipcallControlModel?.GetBerthText(null);
|
||||
this.textBlockCallsign.Text = this.ShipcallControlModel?.Ship?.Callsign;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival)
|
||||
{
|
||||
this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Eta?.ToString("dd.MM. HH:mm");
|
||||
}
|
||||
if ((this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Departure) || (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Shifting))
|
||||
{
|
||||
this.labelETA.Text = "ETD";
|
||||
this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Etd?.ToString("dd.MM. HH:mm");
|
||||
}
|
||||
this.textBlockETA.Text = this.ShipcallControlModel?.GetETAETD(true);
|
||||
|
||||
this.textBlockIMO.Text = this.ShipcallControlModel?.Ship?.Imo.ToString();
|
||||
this.textBlockLengthWidth.Text = $"{this.ShipcallControlModel?.Ship?.Length} / {this.ShipcallControlModel?.Ship?.Width}";
|
||||
@ -294,6 +280,7 @@ namespace BreCalClient
|
||||
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelETA.Text = "ETD";
|
||||
this.labelETAETDAgent.Content = "ETD";
|
||||
this.labelETAETDMooring.Content = "ETD";
|
||||
this.labelETAETDPilot.Content = "ETD";
|
||||
@ -315,6 +302,9 @@ namespace BreCalClient
|
||||
|
||||
if (this.ShipcallControlModel != null)
|
||||
{
|
||||
this.textBlockHarbour.Text = ((ShipcallControlModel != null) && (ShipcallControlModel.Shipcall != null) && BreCalLists.PortLookupDict.ContainsKey(ShipcallControlModel.Shipcall.PortId)) ?
|
||||
BreCalLists.PortLookupDict[ShipcallControlModel.Shipcall.PortId].Name : "";
|
||||
Extensions.ParticipantType? lastToUpdate = this.ShipcallControlModel?.LastParticipantTypeToUpdate();
|
||||
|
||||
Times? agencyTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
|
||||
if (agencyTimes != null)
|
||||
@ -323,7 +313,19 @@ namespace BreCalClient
|
||||
this.labelAgencyETAETDValue.Content = agencyTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||
this.textBlockAgencyRemarks.Text = agencyTimes.Remarks.TruncateDots(50);
|
||||
this.textBlockAgencyBerthRemarks.Text = agencyTimes.BerthInfo.TruncateDots(50);
|
||||
this.textBlockDraft.Text = ShipcallControlModel?.Shipcall?.Draft?.ToString("N2");
|
||||
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.AGENCY);
|
||||
this.labelLastChangeAgency.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||
Grid.SetRowSpan(this.labelAgent, 1);
|
||||
if(lastToUpdate == Extensions.ParticipantType.AGENCY)
|
||||
{
|
||||
this.labelLastChangeAgency.Foreground = Brushes.White;
|
||||
this.labelLastChangeAgency.FontWeight = FontWeights.DemiBold;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelLastChangeAgency.Foreground = Brushes.LightGray;
|
||||
this.labelLastChangeAgency.FontWeight = FontWeights.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -332,7 +334,7 @@ namespace BreCalClient
|
||||
this.labelAgencyETAETDValue.Content = "- / -";
|
||||
this.textBlockAgencyRemarks.Text = "";
|
||||
this.textBlockAgencyBerthRemarks.Text = "";
|
||||
this.textBlockDraft.Text = "";
|
||||
Grid.SetRowSpan(this.labelAgent, 2);
|
||||
}
|
||||
|
||||
Times? mooringTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.MOORING);
|
||||
@ -356,12 +358,26 @@ namespace BreCalClient
|
||||
labelTimesMooringATD.Content = mooringTimes.Atd.Value.ToString("dd.MM.yyyy HH:mm");
|
||||
}
|
||||
|
||||
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.MOORING);
|
||||
this.labelLastChangeMooring.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||
Grid.SetRowSpan(this.labelMooring, 1);
|
||||
if (lastToUpdate == Extensions.ParticipantType.MOORING)
|
||||
{
|
||||
this.labelLastChangeMooring.Foreground = Brushes.White;
|
||||
this.labelLastChangeMooring.FontWeight = FontWeights.DemiBold;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelLastChangeMooring.Foreground = Brushes.LightGray;
|
||||
this.labelLastChangeMooring.FontWeight = FontWeights.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelMooringETAETDValue.Content = "- / ";
|
||||
this.textBlockMooringRemarks.Text = "";
|
||||
this.imageMooringLocked.Visibility = Visibility.Hidden;
|
||||
Grid.SetRowSpan(this.labelMooring, 2);
|
||||
}
|
||||
|
||||
Times? portAuthorityTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
||||
@ -375,12 +391,27 @@ namespace BreCalClient
|
||||
{
|
||||
labelPortAuthorityLockTime.Content = portAuthorityTimes.LockTime.Value.ToString("dd.MM.yyyy HH:mm");
|
||||
}
|
||||
|
||||
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
|
||||
this.labelLastChangePortAuthority.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||
Grid.SetRowSpan(this.labelPortAuthority, 1);
|
||||
if (lastToUpdate == Extensions.ParticipantType.PORT_ADMINISTRATION)
|
||||
{
|
||||
this.labelLastChangePortAuthority.Foreground = Brushes.White;
|
||||
this.labelLastChangePortAuthority.FontWeight = FontWeights.DemiBold;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelLastChangePortAuthority.Foreground = Brushes.LightGray;
|
||||
this.labelLastChangePortAuthority.FontWeight = FontWeights.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelPortAuthorityETAETDValue.Content = "- / -";
|
||||
this.textBlockPortAuthorityRemarks.Text = "";
|
||||
this.imagePortAuthorityLocked.Visibility = Visibility.Hidden;
|
||||
Grid.SetRowSpan(this.labelPortAuthority, 2);
|
||||
}
|
||||
|
||||
Times? pilotTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PILOT);
|
||||
@ -389,12 +420,27 @@ namespace BreCalClient
|
||||
this.labelPilotETAETDValue.Content = pilotTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||
this.textBlockPilotRemarks.Text = pilotTimes.Remarks.TruncateDots(50);
|
||||
this.imagePilotLocked.Visibility = (pilotTimes.EtaBerthFixed ?? false) ? Visibility.Visible : Visibility.Hidden;
|
||||
|
||||
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.PILOT);
|
||||
this.labelLastChangePilot.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||
Grid.SetRowSpan(this.labelPilot, 1);
|
||||
if (lastToUpdate == Extensions.ParticipantType.PILOT)
|
||||
{
|
||||
this.labelLastChangePilot.Foreground = Brushes.White;
|
||||
this.labelLastChangePilot.FontWeight = FontWeights.DemiBold;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelLastChangePilot.Foreground = Brushes.LightGray;
|
||||
this.labelLastChangePilot.FontWeight = FontWeights.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelPilotETAETDValue.Content = "- / -";
|
||||
this.textBlockPilotRemarks.Text = "";
|
||||
this.imagePilotLocked.Visibility = Visibility.Hidden;
|
||||
Grid.SetRowSpan(this.labelPilot, 2);
|
||||
}
|
||||
|
||||
Times? tugTimes = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.TUG);
|
||||
@ -403,12 +449,27 @@ namespace BreCalClient
|
||||
this.labelTugETAETDValue.Content = tugTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||
this.textBlockTugRemarks.Text = tugTimes.Remarks.TruncateDots(50);
|
||||
this.imageTugLocked.Visibility = (tugTimes.EtaBerthFixed ?? false) ? Visibility.Visible : Visibility.Hidden;
|
||||
|
||||
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.TUG);
|
||||
this.labelLastChangeTug.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||
Grid.SetRowSpan(this.labelTug, 1);
|
||||
if (lastToUpdate == Extensions.ParticipantType.TUG)
|
||||
{
|
||||
this.labelLastChangeTug.Foreground = Brushes.White;
|
||||
this.labelLastChangeTug.FontWeight = FontWeights.DemiBold;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelLastChangeTug.Foreground = Brushes.LightGray;
|
||||
this.labelLastChangeTug.FontWeight = FontWeights.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelTugETAETDValue.Content = "- / -";
|
||||
this.textBlockTugRemarks.Text = "";
|
||||
this.imageTugLocked.Visibility = Visibility.Hidden;
|
||||
Grid.SetRowSpan(this.labelTug, 2);
|
||||
}
|
||||
|
||||
this.rowDefinitionTerminalBerth.Height = (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival) ? new(14) : new(0);
|
||||
@ -422,6 +483,19 @@ namespace BreCalClient
|
||||
this.labelOperationsStart.Content = terminalTimes.DisplayTime(this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival);
|
||||
this.textBlockTerminalRemarks.Text = terminalTimes.Remarks.TruncateDots(40);
|
||||
this.textBlockTerminalBerthRemarks.Text = terminalTimes.BerthInfo.TruncateDots(40);
|
||||
DateTime? lc = this.ShipcallControlModel?.GetLastChangeForType(Extensions.ParticipantType.TERMINAL);
|
||||
this.labelLastChangeTerminal.Content = lc.HasValue ? lc.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||
Grid.SetRowSpan(this.labelTerminal, 1);
|
||||
if (lastToUpdate == Extensions.ParticipantType.TERMINAL)
|
||||
{
|
||||
this.labelLastChangeTerminal.Foreground = Brushes.White;
|
||||
this.labelLastChangeTerminal.FontWeight = FontWeights.DemiBold;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.labelLastChangeTerminal.Foreground = Brushes.LightGray;
|
||||
this.labelLastChangeTerminal.FontWeight = FontWeights.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -429,6 +503,7 @@ namespace BreCalClient
|
||||
this.labelOperationsStart.Content = "";
|
||||
this.textBlockTerminalRemarks.Text = "";
|
||||
this.textBlockTerminalBerthRemarks.Text = "";
|
||||
Grid.SetRowSpan(this.labelTerminal, 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -118,6 +118,8 @@ namespace BreCalClient
|
||||
}
|
||||
}
|
||||
|
||||
public bool AllowPortChange { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region public methods
|
||||
@ -217,7 +219,7 @@ namespace BreCalClient
|
||||
return berthText;
|
||||
}
|
||||
|
||||
public string GetETAETD()
|
||||
public string GetETAETD(bool useShortVersion = false)
|
||||
{
|
||||
DateTime theDate = DateTime.Now;
|
||||
if(this.Shipcall != null)
|
||||
@ -241,6 +243,8 @@ namespace BreCalClient
|
||||
theDate = agentTimes.EtdBerth.Value;
|
||||
}
|
||||
}
|
||||
if(useShortVersion)
|
||||
return theDate.ToString("dd.MM. HH:mm");
|
||||
return theDate.ToString();
|
||||
}
|
||||
|
||||
@ -309,6 +313,42 @@ namespace BreCalClient
|
||||
return true;
|
||||
}
|
||||
|
||||
public DateTime? GetLastChangeForType(Extensions.ParticipantType type)
|
||||
{
|
||||
DateTime? lastChange = null;
|
||||
Times? times = GetTimesForParticipantType(type);
|
||||
if(times != null)
|
||||
{
|
||||
if (times.Modified.HasValue) lastChange = times.Modified.Value;
|
||||
else lastChange = times.Created;
|
||||
}
|
||||
return lastChange;
|
||||
}
|
||||
|
||||
public Extensions.ParticipantType? LastParticipantTypeToUpdate()
|
||||
{
|
||||
Extensions.ParticipantType? last = null;
|
||||
DateTime min = DateTime.MinValue;
|
||||
foreach(Times times in this.Times)
|
||||
{
|
||||
if (times.Modified.HasValue)
|
||||
{
|
||||
if (times.Modified.Value > min)
|
||||
{
|
||||
min = times.Modified.Value;
|
||||
last = (Extensions.ParticipantType)times.ParticipantType;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(times.Created > min)
|
||||
{
|
||||
min = times.Created;
|
||||
last = (Extensions.ParticipantType)times.ParticipantType;
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region helper
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:RoleEditor"
|
||||
mc:Ignorable="d"
|
||||
Title="Edit berth" Height="188" Width="450" Loaded="Window_Loaded">
|
||||
Title="Edit berth" Height="216" Width="450" Loaded="Window_Loaded">
|
||||
<Grid x:Name="berthGrid">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width=".3*" />
|
||||
@ -16,6 +16,7 @@
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="28" />
|
||||
</Grid.RowDefinitions>
|
||||
@ -45,7 +46,9 @@
|
||||
</Grid>
|
||||
<Label Content="Uses lock" HorizontalAlignment="Right" Grid.Row="3" />
|
||||
<CheckBox x:Name="checkBoxLock" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" Margin="2" IsChecked="{Binding Path=Lock, Mode=OneWay}"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="5" Orientation="Horizontal" FlowDirection="RightToLeft">
|
||||
<Label Content="Port" HorizontalAlignment="Right" Grid.Row="4" />
|
||||
<ComboBox Name="comboBoxPorts" Margin="2" Grid.Column="1" Grid.Row="4" SelectedItem="{Binding Port, Mode=OneWay}" />
|
||||
<StackPanel Grid.Column="1" Grid.Row="6" Orientation="Horizontal" FlowDirection="RightToLeft">
|
||||
<Button x:Name="buttonCancel" Width="80" Content="Cancel" Margin="2" Click="buttonCancel_Click" />
|
||||
<Button x:Name="buttonOK" Width="80" Content="OK" Margin="2" Click="buttonOK_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
@ -20,6 +20,8 @@ namespace RoleEditor
|
||||
|
||||
public List<Participant> Authorities { get; } = new List<Participant>();
|
||||
|
||||
public List<Port> Ports { get; } = new List<Port>();
|
||||
|
||||
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.DialogResult = false;
|
||||
@ -43,6 +45,12 @@ namespace RoleEditor
|
||||
else
|
||||
this.Berth.Authority_Id = null;
|
||||
|
||||
this.Berth.Port = this.comboBoxPorts.SelectedItem as Port;
|
||||
if (this.Berth.Port != null)
|
||||
this.Berth.Port_Id = this.Berth.Port.Id;
|
||||
else
|
||||
this.Berth.Port_Id = null;
|
||||
|
||||
this.DialogResult = true;
|
||||
this.Close();
|
||||
}
|
||||
@ -52,6 +60,7 @@ namespace RoleEditor
|
||||
this.DataContext = this.Berth;
|
||||
this.comboBoxParticipants.ItemsSource = this.Owners;
|
||||
this.comboBoxAuthorities.ItemsSource = this.Authorities;
|
||||
this.comboBoxPorts.ItemsSource = this.Ports;
|
||||
}
|
||||
|
||||
private void buttonResetParticipant_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
xmlns:local="clr-namespace:RoleEditor"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
mc:Ignorable="d"
|
||||
Title="Bremen calling admin editor" Height="670" Width="800" Icon="Resources/lock_preferences.ico" Loaded="Window_Loaded">
|
||||
Title="Bremen calling admin editor" Height="670" Width="1024" Icon="Resources/lock_preferences.ico" Loaded="Window_Loaded">
|
||||
<Grid>
|
||||
<TabControl>
|
||||
<TabItem Header="Participant, users and roles">
|
||||
@ -16,8 +16,9 @@
|
||||
<RowDefinition Height=".5*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width=".5*" />
|
||||
<ColumnDefinition Width=".5*" />
|
||||
<ColumnDefinition Width=".4*" />
|
||||
<ColumnDefinition Width=".3*" />
|
||||
<ColumnDefinition Width=".3*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<GroupBox Header="Participant" Margin="2">
|
||||
<Grid>
|
||||
@ -82,6 +83,69 @@
|
||||
</Button>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Port Assignment" Margin="2" Grid.Row="0" Grid.Column="1">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="60" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ListBox x:Name="listBoxPortAssignment" Margin="2" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" />
|
||||
<Button x:Name="buttonAddPortAssignment" Margin="2" Grid.Row="0" Grid.Column="1" Click="buttonAddPortAssignment_Click">
|
||||
<Image Source="./Resources/arrow_left_green.png"/>
|
||||
</Button>
|
||||
<Button x:Name="buttonRemovePortAssignment" Margin="2" Grid.Row="1" Grid.Column="1" Click="buttonRemovePortAssignment_Click">
|
||||
<Image Source="./Resources/delete2.png"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Ports" Margin="2" Grid.Row="0" Grid.Column="2">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28"/>
|
||||
<RowDefinition Height="28"/>
|
||||
<RowDefinition Height="28"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160" />
|
||||
<ColumnDefinition Width=".38*" />
|
||||
<ColumnDefinition Width=".62*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ListBox x:Name="listBoxPort" Margin="2" Grid.RowSpan="4" SelectionChanged="listBoxPort_SelectionChanged">
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuItemNewPort" Header="New.." Click="menuItemNewPort_Click">
|
||||
<MenuItem.Icon>
|
||||
<Image Source="Resources/add.png" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuItemDeletePort" Header="Delete" Click="menuItemDeletePort_Click">
|
||||
<MenuItem.Icon>
|
||||
<Image Source="Resources/delete2.png" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
</ListBox>
|
||||
<Label Grid.Row="0" Grid.Column="1" Content="Name" HorizontalAlignment="Right"/>
|
||||
<Label Grid.Row="1" Grid.Column="1" Content="Locode" HorizontalAlignment="Right"/>
|
||||
<TextBox x:Name="textBoxPortName" Grid.Row="0" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" MaxLength="128"/>
|
||||
<TextBox x:Name="textBoxPortLocode" Grid.Row="1" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" MaxLength="5" />
|
||||
|
||||
<Button x:Name="buttonPortSave" Grid.Row="2" Grid.Column="2" Click="buttonPortSave_Click" Margin="2">
|
||||
<DockPanel>
|
||||
<Image Source="./Resources/disk_blue.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="16"/>
|
||||
<TextBlock Text="Save" VerticalAlignment="Center" DockPanel.Dock="Right"/>
|
||||
</DockPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
<GroupBox Header="User" Margin="2" Grid.Row="1">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
@ -145,7 +209,7 @@
|
||||
</Button>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Role" Margin="2" Grid.Column="1">
|
||||
<GroupBox Header="Role" Margin="2" Grid.Column="1" Grid.Row="1">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28"/>
|
||||
@ -199,7 +263,7 @@
|
||||
</Button>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Securable" Margin="2" Grid.Row="1" Grid.Column="1">
|
||||
<GroupBox Header="Securable" Margin="2" Grid.Row="1" Grid.Column="2">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28"/>
|
||||
@ -276,6 +340,7 @@
|
||||
<DataGridCheckBoxColumn Header="Lock" Binding="{Binding Path=Lock}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="Terminal" Binding="{Binding Path=Terminal, Mode=OneWay}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="Authority" Binding="{Binding Path=Authority_Text, Mode=OneWay}" IsReadOnly="True" />
|
||||
<DataGridTextColumn Header="Port" Binding="{Binding Path=Port}" IsReadOnly="True" />
|
||||
<DataGridTextColumn Header="Deleted" Binding="{Binding Path=Deleted, Mode=OneWay}" IsReadOnly="True" />
|
||||
</DataGrid.Columns>
|
||||
</local:ENIDataGrid>
|
||||
|
||||
@ -38,6 +38,8 @@ namespace RoleEditor
|
||||
private readonly ObservableCollection<SecurableAssignment> _assignedSecurables = new ObservableCollection<SecurableAssignment>();
|
||||
private readonly ObservableCollection<Berth> _berths = new ObservableCollection<Berth>();
|
||||
private readonly ObservableCollection<Ship> _ships = new ObservableCollection<Ship>();
|
||||
private readonly ObservableCollection<Port> _ports = new ObservableCollection<Port>();
|
||||
private readonly ObservableCollection<PortAssignment> _assignedPorts = new ObservableCollection<PortAssignment>();
|
||||
private DBManager _dbManager;
|
||||
|
||||
#endregion
|
||||
@ -77,6 +79,10 @@ namespace RoleEditor
|
||||
_securables.Add(s);
|
||||
this.listBoxSecurables.ItemsSource = _securables;
|
||||
|
||||
// load all ports
|
||||
foreach (Port port in await Port.LoadAll(_dbManager)) _ports.Add(port);
|
||||
this.listBoxPort.ItemsSource = _ports;
|
||||
|
||||
// load all berths
|
||||
foreach (Berth b in await Berth.LoadAll(_dbManager))
|
||||
{
|
||||
@ -89,6 +95,10 @@ namespace RoleEditor
|
||||
{
|
||||
b.Authority = participants.Where(p => p.Id == b.Authority_Id).FirstOrDefault();
|
||||
}
|
||||
if (b.Port_Id != null)
|
||||
{
|
||||
b.Port = _ports.Where(p => p.Id == b.Port_Id).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
this.dataGridBerths.Initialize();
|
||||
this.dataGridBerths.ItemsSource = _berths;
|
||||
@ -112,12 +122,14 @@ namespace RoleEditor
|
||||
|
||||
this.dataGridShips.CreateRequested += DataGridShips_CreateRequested;
|
||||
this.dataGridShips.EditRequested += DataGridShips_EditRequested;
|
||||
this.dataGridShips.DeleteRequested += DataGridShips_DeleteRequested;
|
||||
this.dataGridShips.DeleteRequested += DataGridShips_DeleteRequested;
|
||||
|
||||
|
||||
// set other item sources (filled later after selection)
|
||||
this.listBoxUser.ItemsSource = _users;
|
||||
this.listBoxRoleSecurables.ItemsSource = _assignedSecurables;
|
||||
this.listBoxUserRoles.ItemsSource = _assignedRoles;
|
||||
this.listBoxPortAssignment.ItemsSource = _assignedPorts;
|
||||
|
||||
this.comboBoxParticipantType.ItemsSource = EnumHelper.GetAllValuesAndDescription(typeof(Participant.ParticipantType));
|
||||
|
||||
@ -192,6 +204,7 @@ namespace RoleEditor
|
||||
ebd.Berth = b;
|
||||
ebd.Owners.AddRange(this._terminals);
|
||||
ebd.Authorities.AddRange(this._authorities);
|
||||
ebd.Ports.AddRange(this._ports.Where(p => !p.IsDeleted));
|
||||
if (ebd.ShowDialog() ?? false)
|
||||
{
|
||||
await b.Save(_dbManager);
|
||||
@ -208,6 +221,7 @@ namespace RoleEditor
|
||||
ebd.Berth = b;
|
||||
ebd.Owners.AddRange(this._terminals);
|
||||
ebd.Authorities.AddRange(this._authorities);
|
||||
ebd.Ports.AddRange(_ports.Where(p => !p.IsDeleted));
|
||||
if (ebd.ShowDialog() ?? false)
|
||||
{
|
||||
_berths.Add(b);
|
||||
@ -386,6 +400,59 @@ namespace RoleEditor
|
||||
}
|
||||
}
|
||||
|
||||
private async void buttonPortSave_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Port? p = this.listBoxPort.SelectedItem as Port;
|
||||
if (p != null)
|
||||
{
|
||||
p.Name = this.textBoxPortName.Text.Trim();
|
||||
p.Locode = this.textBoxPortLocode.Text.Trim();
|
||||
await p.Save(_dbManager);
|
||||
this.listBoxPort.ItemsSource = null;
|
||||
this.listBoxPort.ItemsSource = _ports;
|
||||
this.listBoxPort.SelectedItem = p;
|
||||
}
|
||||
}
|
||||
|
||||
private async void buttonAddPortAssignment_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if ((this.listBoxPort.SelectedItem is Port p) && (this.listBoxParticipant.SelectedItem is Participant pa))
|
||||
{
|
||||
// test if assignment is already present
|
||||
bool foundMatchingAssignment = false;
|
||||
foreach (PortAssignment portAssignment in _assignedPorts)
|
||||
{
|
||||
if ((portAssignment.PortId == p.Id) && (portAssignment.ParticipantId == pa.Id))
|
||||
{
|
||||
foundMatchingAssignment = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMatchingAssignment)
|
||||
{
|
||||
PortAssignment portAssignment = new PortAssignment();
|
||||
portAssignment.PortId = (int)p.Id;
|
||||
portAssignment.ParticipantId = (int)pa.Id;
|
||||
portAssignment.AssignedParticipant = pa;
|
||||
portAssignment.AssignedPort = p;
|
||||
await portAssignment.Save(_dbManager);
|
||||
_assignedPorts.Add(portAssignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void buttonRemovePortAssignment_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PortAssignment? pa = this.listBoxPortAssignment.SelectedItem as PortAssignment;
|
||||
if (pa != null)
|
||||
{
|
||||
await pa.Delete(_dbManager);
|
||||
if (_assignedPorts.Contains(pa))
|
||||
_assignedPorts.Remove(pa);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region listbox selection callbacks
|
||||
@ -430,6 +497,19 @@ namespace RoleEditor
|
||||
foreach (User u in await User.LoadForParticipant(p, _dbManager))
|
||||
_users.Add(u);
|
||||
}
|
||||
|
||||
// -> load port assignments for this participant selection
|
||||
this._assignedPorts.Clear();
|
||||
if(p != null)
|
||||
{
|
||||
foreach (PortAssignment pa in await PortAssignment.LoadForParticipant(p, this._dbManager))
|
||||
{
|
||||
foreach (Port port in this._ports)
|
||||
if (pa.PortId == port.Id)
|
||||
pa.AssignedPort = port;
|
||||
_assignedPorts.Add(pa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void listBoxRoles_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
@ -496,6 +576,13 @@ namespace RoleEditor
|
||||
this.textBoxSecurableName.Text = (s != null) ? s.Name : string.Empty;
|
||||
}
|
||||
|
||||
private void listBoxPort_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
Port? p = this.listBoxPort.SelectedItem as Port;
|
||||
this.textBoxPortName.Text = (p != null) ? p.Name : string.Empty;
|
||||
this.textBoxPortLocode.Text = (p != null) ? p.Locode : string.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region menuitem callbacks
|
||||
@ -597,6 +684,29 @@ namespace RoleEditor
|
||||
}
|
||||
}
|
||||
|
||||
private void menuItemNewPort_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Port p = new();
|
||||
this._ports.Add(p);
|
||||
this.listBoxPort.SelectedItem = p;
|
||||
}
|
||||
|
||||
private async void menuItemDeletePort_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.listBoxPort.SelectedItem is Port p)
|
||||
{
|
||||
await p.Delete(_dbManager);
|
||||
this._ports.Remove(p);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Excel import
|
||||
@ -634,7 +744,7 @@ namespace RoleEditor
|
||||
{
|
||||
if (reader.FieldCount < 2)
|
||||
{
|
||||
throw new InvalidDataException("Sheet must have at least 2 Columns of data");
|
||||
throw new InvalidDataException("Sheet must have at least 3 Columns of data");
|
||||
}
|
||||
|
||||
if (reader.IsDBNull(0) && reader.IsDBNull(1)) continue;
|
||||
@ -649,8 +759,20 @@ namespace RoleEditor
|
||||
if (_berths.Any(predicate: x => (x.Name != null) && x.Name.Equals(berth_name, StringComparison.OrdinalIgnoreCase)))
|
||||
continue;
|
||||
|
||||
string port_name = "";
|
||||
if (!reader.IsDBNull(2)) port_name = reader.GetString(2);
|
||||
|
||||
// find port in list
|
||||
if(!_ports.Any(x => (x.Name != null) && x.Name.Equals(port_name, StringComparison.OrdinalIgnoreCase)))
|
||||
continue;
|
||||
|
||||
Port port = _ports.First(x => (x.Name != null) && x.Name.Equals(port_name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
Berth b = new Berth();
|
||||
b.Name = berth_name;
|
||||
b.Port = port;
|
||||
b.Port_Id = port.Id;
|
||||
|
||||
bool found_participant = false;
|
||||
|
||||
foreach(Participant p in this._participants)
|
||||
@ -801,6 +923,6 @@ namespace RoleEditor
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
6
src/RoleEditor/Properties/Settings.Designer.cs
generated
6
src/RoleEditor/Properties/Settings.Designer.cs
generated
@ -12,7 +12,7 @@ namespace RoleEditor.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
@ -25,8 +25,8 @@ namespace RoleEditor.Properties {
|
||||
|
||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling;" +
|
||||
"Port=33306")]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_" +
|
||||
"test;Port=33306")]
|
||||
public string ConnectionString {
|
||||
get {
|
||||
return ((string)(this["ConnectionString"]));
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="ConnectionString" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling;Port=33306</Value>
|
||||
<Value Profile="(Default)">Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_test;Port=33306</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
@ -6,6 +6,8 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ApplicationIcon>Resources\lock_preferences.ico</ApplicationIcon>
|
||||
<FileVersion>1.6.0.4</FileVersion>
|
||||
<AssemblyVersion>1.6.0.4</AssemblyVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@ -1,12 +1,7 @@
|
||||
// Copyright (c) 2023- schick Informatik
|
||||
// Description: Model class for berth entity
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace brecal.model
|
||||
{
|
||||
@ -23,10 +18,14 @@ namespace brecal.model
|
||||
|
||||
public uint? Authority_Id { get; set; }
|
||||
|
||||
public uint? Port_Id { get; set; }
|
||||
|
||||
public Participant? Owner { get; set; }
|
||||
|
||||
public Participant? Authority { get; set; }
|
||||
|
||||
public Port? Port { get; set; }
|
||||
|
||||
public string? Terminal { get { if (Owner != null) return Owner.Name; else return "n/a"; } }
|
||||
|
||||
public string? Authority_Text { get { if (Authority != null) return Authority.Name; else return "n/a"; } }
|
||||
@ -48,12 +47,12 @@ namespace brecal.model
|
||||
|
||||
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
|
||||
{
|
||||
cmd.CommandText = "SELECT id, name, owner_id, authority_id, `lock`, created, modified, deleted FROM berth";
|
||||
cmd.CommandText = "SELECT id, name, owner_id, authority_id, port_id, `lock`, created, modified, deleted FROM berth";
|
||||
}
|
||||
|
||||
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||
{
|
||||
List<DbEntity> result = new List<DbEntity>();
|
||||
List<DbEntity> result = new();
|
||||
while (reader.Read())
|
||||
{
|
||||
Berth b = new();
|
||||
@ -61,10 +60,11 @@ namespace brecal.model
|
||||
if (!reader.IsDBNull(1)) b.Name = reader.GetString(1);
|
||||
if (!reader.IsDBNull(2)) b.Owner_Id = (uint) reader.GetInt32(2);
|
||||
if (!reader.IsDBNull(3)) b.Authority_Id = (uint) reader.GetInt32(3);
|
||||
if (!reader.IsDBNull(4)) b.Lock = reader.GetBoolean(4);
|
||||
if (!reader.IsDBNull(5)) b.Created = reader.GetDateTime(5);
|
||||
if (!reader.IsDBNull(6)) b.Modified = reader.GetDateTime(6);
|
||||
if (!reader.IsDBNull(7)) b.Deleted = reader.GetInt16(7);
|
||||
if (!reader.IsDBNull(4)) b.Port_Id = (uint) reader.GetInt32(4);
|
||||
if (!reader.IsDBNull(5)) b.Lock = reader.GetBoolean(5);
|
||||
if (!reader.IsDBNull(6)) b.Created = reader.GetDateTime(6);
|
||||
if (!reader.IsDBNull(7)) b.Modified = reader.GetDateTime(7);
|
||||
if (!reader.IsDBNull(8)) b.Deleted = reader.GetInt16(8);
|
||||
result.Add(b);
|
||||
}
|
||||
return result;
|
||||
@ -76,7 +76,7 @@ namespace brecal.model
|
||||
|
||||
public override void SetCreate(IDbCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "INSERT INTO berth (owner_id, authority_id, name, `lock`) VALUES ( @PID, @AID, @NAME, @LOCK)";
|
||||
cmd.CommandText = "INSERT INTO berth (owner_id, authority_id, port_id, name, `lock`) VALUES ( @PID, @AID, @PO_ID, @NAME, @LOCK)";
|
||||
this.SetParameters(cmd);
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ namespace brecal.model
|
||||
|
||||
public override void SetUpdate(IDbCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "UPDATE berth SET name = @NAME, owner_id = @PID, authority_id = @AID, `lock` = @LOCK WHERE id = @ID";
|
||||
cmd.CommandText = "UPDATE berth SET name = @NAME, owner_id = @PID, authority_id = @AID, port_id = @PO_ID, `lock` = @LOCK WHERE id = @ID";
|
||||
this.SetParameters(cmd);
|
||||
}
|
||||
|
||||
@ -109,14 +109,19 @@ namespace brecal.model
|
||||
|
||||
IDbDataParameter pid = cmd.CreateParameter();
|
||||
pid.ParameterName = "PID";
|
||||
pid.Value = this.Owner_Id;
|
||||
pid.Value = this.Owner_Id.HasValue ? this.Owner_Id.Value : DBNull.Value;
|
||||
cmd.Parameters.Add(pid);
|
||||
|
||||
IDbDataParameter aid = cmd.CreateParameter();
|
||||
aid.ParameterName = "AID";
|
||||
aid.Value = this.Authority_Id;
|
||||
aid.Value = this.Authority_Id.HasValue ? this.Authority_Id.Value : DBNull.Value;
|
||||
cmd.Parameters.Add(aid);
|
||||
|
||||
IDbDataParameter poid = cmd.CreateParameter();
|
||||
poid.ParameterName = "PO_ID";
|
||||
poid.Value = this.Port_Id.HasValue ? this.Port_Id.Value : DBNull.Value;
|
||||
cmd.Parameters.Add(poid);
|
||||
|
||||
IDbDataParameter name = cmd.CreateParameter();
|
||||
name.ParameterName = "NAME";
|
||||
name.Value = this.Name;
|
||||
|
||||
@ -70,7 +70,7 @@ namespace brecal.model
|
||||
|
||||
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||
{
|
||||
List<DbEntity> result = new List<DbEntity>();
|
||||
List<DbEntity> result = new();
|
||||
while (reader.Read())
|
||||
{
|
||||
Participant p = new();
|
||||
|
||||
115
src/brecal.model/Port.cs
Normal file
115
src/brecal.model/Port.cs
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2023- schick Informatik
|
||||
// Description: Port entity
|
||||
|
||||
using System.Data;
|
||||
|
||||
namespace brecal.model
|
||||
{
|
||||
public class Port : DbEntity
|
||||
{
|
||||
|
||||
#region Properties
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string? Locode { get; set; }
|
||||
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region overrides
|
||||
|
||||
public override void SetCreate(IDbCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "INSERT INTO port (name, locode) VALUES ( @NAME, @LOCODE)";
|
||||
this.SetParameters(cmd);
|
||||
}
|
||||
|
||||
public override void SetDelete(IDbCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "UPDATE port SET deleted = 1 WHERE id = @ID";
|
||||
IDataParameter idParam = cmd.CreateParameter();
|
||||
idParam.ParameterName = "ID";
|
||||
idParam.Value = this.Id;
|
||||
cmd.Parameters.Add(idParam);
|
||||
}
|
||||
|
||||
public override void SetUpdate(IDbCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "UPDATE port set name = @NAME, locode = @LOCODE WHERE id = @ID";
|
||||
this.SetParameters(cmd);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public static methods
|
||||
|
||||
public static async Task<List<Port>> LoadAll(IDBManager manager)
|
||||
{
|
||||
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems);
|
||||
List<Port> result = new();
|
||||
foreach (Port p in loadResultList.Cast<Port>())
|
||||
result.Add(p);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
|
||||
{
|
||||
cmd.CommandText = "SELECT id, name, locode, created, modified, deleted FROM port WHERE deleted = 0";
|
||||
}
|
||||
|
||||
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||
{
|
||||
List<DbEntity> result = new();
|
||||
while (reader.Read())
|
||||
{
|
||||
Port p = new();
|
||||
p.Id = (uint)reader.GetInt32(0);
|
||||
if (!reader.IsDBNull(1)) p.Name = reader.GetString(1);
|
||||
if (!reader.IsDBNull(2)) p.Locode = reader.GetString(2);
|
||||
if (!reader.IsDBNull(3)) p.Created = reader.GetDateTime(3);
|
||||
if (!reader.IsDBNull(4)) p.Modified = reader.GetDateTime(4);
|
||||
if (!reader.IsDBNull(5)) p.IsDeleted = reader.GetBoolean(5);
|
||||
result.Add(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region private methods
|
||||
|
||||
private void SetParameters(IDbCommand cmd)
|
||||
{
|
||||
IDbDataParameter name = cmd.CreateParameter();
|
||||
name.ParameterName = "NAME";
|
||||
name.Value = this.Name;
|
||||
cmd.Parameters.Add(name);
|
||||
|
||||
IDbDataParameter desc = cmd.CreateParameter();
|
||||
desc.ParameterName = "LOCODE";
|
||||
desc.Value = this.Locode;
|
||||
cmd.Parameters.Add(desc);
|
||||
|
||||
IDataParameter idParam = cmd.CreateParameter();
|
||||
idParam.ParameterName = "ID";
|
||||
idParam.Value = this.Id;
|
||||
cmd.Parameters.Add(idParam);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region overrides
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name} ({Locode})";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
111
src/brecal.model/PortAssignment.cs
Normal file
111
src/brecal.model/PortAssignment.cs
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2023- schick Informatik
|
||||
// Description: Participant Port Map Entity
|
||||
|
||||
using System.Data;
|
||||
|
||||
namespace brecal.model
|
||||
{
|
||||
public class PortAssignment : DbEntity
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public int? ParticipantId { get; set; }
|
||||
|
||||
public int? PortId { get; set; }
|
||||
|
||||
public Participant? AssignedParticipant { get; set; }
|
||||
|
||||
public Port? AssignedPort { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region public static methods
|
||||
|
||||
public static async Task<List<PortAssignment>> LoadForParticipant(Participant? p, IDBManager manager)
|
||||
{
|
||||
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems, args: p);
|
||||
List<PortAssignment> result = new();
|
||||
foreach (PortAssignment pa in loadResultList.Cast<PortAssignment>())
|
||||
{
|
||||
pa.AssignedParticipant = p;
|
||||
result.Add(pa);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void SetLoadQuery(IDbCommand cmd, params object?[] args)
|
||||
{
|
||||
cmd.CommandText = "SELECT id, participant_id, port_id FROM participant_port_map WHERE participant_id = @PID";
|
||||
if (args.Length != 1 || args[0] is not Participant)
|
||||
throw new ArgumentException("loader needs single participant as argument");
|
||||
IDataParameter pid = cmd.CreateParameter();
|
||||
pid.ParameterName = "PID";
|
||||
if (args[0] is Participant p)
|
||||
pid.Value = p.Id;
|
||||
cmd.Parameters.Add(pid);
|
||||
}
|
||||
|
||||
public static List<DbEntity> LoadElems(IDataReader reader)
|
||||
{
|
||||
List<DbEntity> result = new();
|
||||
while (reader.Read())
|
||||
{
|
||||
PortAssignment ra = new();
|
||||
ra.Id = (uint)reader.GetInt32(0);
|
||||
if (!reader.IsDBNull(1)) ra.ParticipantId = reader.GetInt32(1);
|
||||
if (!reader.IsDBNull(2)) ra.PortId = reader.GetInt32(2);
|
||||
result.Add(ra);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region overrides
|
||||
|
||||
public override void SetUpdate(IDbCommand cmd)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetCreate(IDbCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "INSERT INTO participant_port_map (participant_id, port_id) VALUES (@PID, @PORTID)";
|
||||
|
||||
IDbDataParameter participantId = cmd.CreateParameter();
|
||||
participantId.ParameterName = "pID";
|
||||
participantId.Value = this.ParticipantId;
|
||||
cmd.Parameters.Add(participantId);
|
||||
|
||||
IDbDataParameter portId = cmd.CreateParameter();
|
||||
portId.ParameterName = "PORTID";
|
||||
portId.Value = this.PortId;
|
||||
cmd.Parameters.Add(portId);
|
||||
}
|
||||
|
||||
public override void SetDelete(IDbCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "DELETE FROM participant_port_map WHERE id = @ID";
|
||||
|
||||
IDataParameter idParam = cmd.CreateParameter();
|
||||
idParam.ParameterName = "ID";
|
||||
idParam.Value = this.Id;
|
||||
cmd.Parameters.Add(idParam);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (this.AssignedPort == null)
|
||||
{
|
||||
return $"{Id}: <defunct port>";
|
||||
}
|
||||
else
|
||||
{
|
||||
return AssignedPort.Name ?? AssignedPort.Id.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
// Copyright (c) 2023- schick Informatik
|
||||
// Description: Role Entity
|
||||
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace brecal.model
|
||||
{
|
||||
|
||||
@ -17,7 +17,7 @@ namespace brecal.mysql
|
||||
|
||||
public async Task<List<DbEntity>> Load(QueryFunc prepareAction, LoadFunc<IDataReader> loadAction, params object?[] args)
|
||||
{
|
||||
await using MySqlConnection connection = new MySqlConnection(_connectionString);
|
||||
await using MySqlConnection connection = new(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
using MySqlCommand cmd = new();
|
||||
@ -31,7 +31,7 @@ namespace brecal.mysql
|
||||
|
||||
public async Task<object?> ExecuteScalar(Action<IDbCommand> prepareAction)
|
||||
{
|
||||
await using MySqlConnection connection = new MySqlConnection(_connectionString);
|
||||
await using MySqlConnection connection = new(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
using MySqlCommand cmd = new();
|
||||
|
||||
@ -13,6 +13,7 @@ from .api import ships
|
||||
from .api import login
|
||||
from .api import user
|
||||
from .api import history
|
||||
from .api import ports
|
||||
|
||||
from BreCal.brecal_utils.file_handling import get_project_root, ensure_path
|
||||
from BreCal.brecal_utils.test_handling import execute_test_with_pytest, execute_coverage_test
|
||||
@ -66,6 +67,7 @@ def create_app(test_config=None, instance_path=None):
|
||||
app.register_blueprint(login.bp)
|
||||
app.register_blueprint(user.bp)
|
||||
app.register_blueprint(history.bp)
|
||||
app.register_blueprint(ports.bp)
|
||||
|
||||
logging.basicConfig(filename='brecal.log', level=logging.DEBUG, format='%(asctime)s | %(name)s | %(levelname)s | %(message)s')
|
||||
local_db.initPool(os.path.dirname(app.instance_path))
|
||||
|
||||
@ -3,6 +3,7 @@ from flask import Blueprint, request
|
||||
from webargs.flaskparser import parser
|
||||
from .. import impl
|
||||
from ..services.auth_guard import auth_guard
|
||||
from ..services.jwt_handler import decode_jwt
|
||||
import json
|
||||
from BreCal.validators.validation_error import create_dynamic_exception_response
|
||||
|
||||
@ -15,8 +16,11 @@ def GetBerths():
|
||||
|
||||
try:
|
||||
if 'Authorization' in request.headers:
|
||||
token = request.headers.get('Authorization')
|
||||
return impl.berths.GetBerths(token)
|
||||
token = request.headers.get('Authorization')
|
||||
payload = decode_jwt(token.split("Bearer ")[-1])
|
||||
options = {}
|
||||
options["participant_id"] = payload["participant_id"]
|
||||
return impl.berths.GetBerths(options)
|
||||
else:
|
||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import logging
|
||||
from flask import Blueprint, request
|
||||
from .. import impl
|
||||
from ..services.auth_guard import auth_guard
|
||||
from ..services.jwt_handler import decode_jwt
|
||||
import json
|
||||
from BreCal.validators.validation_error import create_dynamic_exception_response
|
||||
|
||||
@ -12,10 +13,15 @@ bp = Blueprint('participants', __name__)
|
||||
def GetParticipant():
|
||||
|
||||
try:
|
||||
if 'Authorization' in request.headers:
|
||||
token = request.headers.get('Authorization')
|
||||
if 'Authorization' in request.headers:
|
||||
payload = decode_jwt(request.headers.get("Authorization").split("Bearer ")[-1])
|
||||
options = {}
|
||||
options["user_id"] = request.args.get("user_id")
|
||||
if "participant_id" in payload:
|
||||
options["participant_id"] = payload["participant_id"]
|
||||
else:
|
||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authorized")
|
||||
|
||||
return impl.participant.GetParticipant(options)
|
||||
else:
|
||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||
|
||||
24
src/server/BreCal/api/ports.py
Normal file
24
src/server/BreCal/api/ports.py
Normal file
@ -0,0 +1,24 @@
|
||||
import logging
|
||||
from flask import Blueprint, request
|
||||
from webargs.flaskparser import parser
|
||||
from .. import impl
|
||||
from ..services.auth_guard import auth_guard
|
||||
import json
|
||||
from BreCal.validators.validation_error import create_dynamic_exception_response
|
||||
|
||||
bp = Blueprint('ports', __name__)
|
||||
|
||||
|
||||
@bp.route('/ports', methods=['get'])
|
||||
@auth_guard() # no restriction by role
|
||||
def GetPorts():
|
||||
|
||||
try:
|
||||
if 'Authorization' in request.headers:
|
||||
token = request.headers.get('Authorization')
|
||||
return impl.ports.GetPorts(token)
|
||||
else:
|
||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||
|
||||
except Exception as ex:
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||
@ -7,6 +7,7 @@ from ..services.auth_guard import auth_guard, check_jwt
|
||||
from BreCal.validators.input_validation import validate_posted_shipcall_data, check_if_user_is_bsmd_type
|
||||
from BreCal.validators.input_validation_shipcall import InputValidationShipcall
|
||||
from BreCal.database.sql_handler import execute_sql_query_standalone
|
||||
from BreCal.services.jwt_handler import decode_jwt
|
||||
from BreCal.validators.validation_error import create_validation_error_response, create_werkzeug_error_response, create_dynamic_exception_response
|
||||
from . import verify_if_request_is_json
|
||||
|
||||
@ -22,7 +23,7 @@ bp = Blueprint('shipcalls', __name__)
|
||||
def GetShipcalls():
|
||||
try:
|
||||
if 'Authorization' in request.headers:
|
||||
token = request.headers.get('Authorization') # see impl/login to see the token encoding, which is a JWT token.
|
||||
token = request.headers.get('Authorization') # see impl/login to see the token encoding, which is a JWT token.
|
||||
|
||||
"""
|
||||
from BreCal.services.jwt_handler import decode_jwt
|
||||
@ -32,14 +33,15 @@ def GetShipcalls():
|
||||
# oneline:
|
||||
payload = decode_jwt(request.headers.get("Authorization").split("Bearer ")[-1])
|
||||
"""
|
||||
payload = decode_jwt(request.headers.get("Authorization").split("Bearer ")[-1])
|
||||
options = {}
|
||||
options["participant_id"] = request.args.get("participant_id")
|
||||
options["past_days"] = request.args.get("past_days", default=1, type=int)
|
||||
options["participant_id"] = payload["participant_id"]
|
||||
|
||||
return impl.shipcalls.GetShipcalls(options)
|
||||
else:
|
||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||
|
||||
@ -61,10 +63,10 @@ def PostShipcalls():
|
||||
# validate the posted shipcall data & the user's authority
|
||||
InputValidationShipcall.evaluate_post_data(user_data, loadedModel, content)
|
||||
return impl.shipcalls.PostShipcalls(loadedModel)
|
||||
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex=ex, status_code=400)
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(traceback.format_exc())
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400, message="bad format")
|
||||
@ -76,23 +78,26 @@ def PutShipcalls():
|
||||
|
||||
try:
|
||||
verify_if_request_is_json(request)
|
||||
|
||||
|
||||
content = request.get_json(force=True)
|
||||
loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True)
|
||||
|
||||
# read the user data from the JWT token (set when login is performed)
|
||||
user_data = check_jwt()
|
||||
|
||||
if not InputValidationShipcall.exists_shipcall_by_id(loadedModel.get("id")):
|
||||
return create_dynamic_exception_response(ex=None, status_code=404, message="no shipcall found with the provided id")
|
||||
|
||||
# validate the PUT shipcall data and the user's authority
|
||||
InputValidationShipcall.evaluate_put_data(user_data, loadedModel, content)
|
||||
return impl.shipcalls.PutShipcalls(loadedModel)
|
||||
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex=ex, status_code=400)
|
||||
|
||||
except werkzeug.exceptions.Forbidden as ex:
|
||||
return create_werkzeug_error_response(ex=ex, status_code=403)
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(traceback.format_exc())
|
||||
return create_dynamic_exception_response(ex=None, status_code=400, message="bad format")
|
||||
|
||||
@ -23,7 +23,7 @@ def GetShips():
|
||||
return impl.ships.GetShips(token)
|
||||
else:
|
||||
return create_dynamic_exception_response(ex=None, status_code=403, message="not authenticated")
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||
|
||||
@ -43,7 +43,7 @@ def PostShip():
|
||||
is_bsmd = check_if_user_is_bsmd_type(user_data)
|
||||
if not is_bsmd:
|
||||
raise ValidationError({"participant_type":f"current user does not belong to BSMD. Cannot post shipcalls. Found user data: {user_data}"})
|
||||
|
||||
|
||||
content = request.get_json(force=True)
|
||||
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True)
|
||||
|
||||
@ -53,7 +53,7 @@ def PostShip():
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex=ex, status_code=400)
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400, message=None)
|
||||
|
||||
@ -71,13 +71,16 @@ def PutShip():
|
||||
content = request.get_json(force=True)
|
||||
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True, unknown=EXCLUDE)
|
||||
|
||||
if not InputValidationShip.exists_ship_by_dict(model=loadedModel):
|
||||
return create_dynamic_exception_response(ex=None, status_code=404, message="no ship found with the provided id")
|
||||
|
||||
# validate the request data & user permissions
|
||||
InputValidationShip.evaluate_put_data(user_data, loadedModel, content)
|
||||
return impl.ships.PutShip(loadedModel)
|
||||
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex=ex, status_code=400)
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||
|
||||
@ -88,10 +91,10 @@ def DeleteShip():
|
||||
|
||||
try:
|
||||
verify_if_request_is_json(request)
|
||||
|
||||
|
||||
# read the user data from the JWT token (set when login is performed)
|
||||
user_data = check_jwt()
|
||||
|
||||
|
||||
if 'id' in request.args:
|
||||
options = {}
|
||||
options["id"] = request.args.get("id")
|
||||
@ -100,12 +103,16 @@ def DeleteShip():
|
||||
|
||||
# validate the request data & user permissions
|
||||
ship_id = request.args.get("id")
|
||||
|
||||
if not InputValidationShip.exists_ship_by_id(id=ship_id):
|
||||
return create_dynamic_exception_response(ex=None, status_code=404, message="no ship found with the provided id")
|
||||
|
||||
InputValidationShip.evaluate_delete_data(user_data, ship_id)
|
||||
return impl.ships.DeleteShip(options)
|
||||
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex=ex, status_code=400)
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ def GetTimes():
|
||||
options = {}
|
||||
options["shipcall_id"] = request.args.get("shipcall_id")
|
||||
return impl.times.GetTimes(options)
|
||||
|
||||
|
||||
except Exception as ex:
|
||||
return create_dynamic_exception_response(ex=ex, status_code=400)
|
||||
|
||||
@ -60,13 +60,16 @@ def PutTimes():
|
||||
|
||||
try:
|
||||
verify_if_request_is_json(request)
|
||||
|
||||
|
||||
content = request.get_json(force=True)
|
||||
loadedModel = model.TimesSchema().load(data=content, many=False, partial=True)
|
||||
|
||||
# read the user data from the JWT token (set when login is performed)
|
||||
user_data = check_jwt()
|
||||
|
||||
|
||||
if not InputValidationTimes.exists_times_by_id(loadedModel.get("id")):
|
||||
return create_dynamic_exception_response(ex=None, status_code=404, message="no times found with the provided id")
|
||||
|
||||
# validate the request
|
||||
InputValidationTimes.evaluate_put_data(user_data, loadedModel, content)
|
||||
return impl.times.PutTimes(loadedModel)
|
||||
@ -91,13 +94,16 @@ def DeleteTimes():
|
||||
# read the user data from the JWT token (set when login is performed)
|
||||
user_data = check_jwt()
|
||||
|
||||
if not InputValidationTimes.exists_times_by_id(options["id"]):
|
||||
return create_dynamic_exception_response(ex=None, status_code=404, message="no times found with the provided id")
|
||||
|
||||
# validate the request
|
||||
InputValidationTimes.evaluate_delete_data(user_data, times_id = request.args.get("id"))
|
||||
|
||||
return impl.times.DeleteTimes(options)
|
||||
else:
|
||||
return create_dynamic_exception_response(ex=None, status_code=400, message="Times delete missing argument: id")
|
||||
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex=ex, status_code=400)
|
||||
|
||||
|
||||
@ -22,15 +22,15 @@ def get_request_code(code_id):
|
||||
class RequestStatusCode(ABC):
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def __call__(self, data):
|
||||
raise NotImplementedError("any default status code object must be callable")
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def status_code(self):
|
||||
raise NotImplementedError("any default status code object should return an integer")
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def response(self, data):
|
||||
raise NotImplementedError("the response method should return a binary json object. typically, json.dumps is used")
|
||||
@ -38,7 +38,7 @@ class RequestStatusCode(ABC):
|
||||
|
||||
def headers(self):
|
||||
return {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
|
||||
class RequestCode_HTTP_200_OK(RequestStatusCode):
|
||||
def __init__(self) -> None:
|
||||
@ -46,13 +46,13 @@ class RequestCode_HTTP_200_OK(RequestStatusCode):
|
||||
|
||||
def __call__(self, data):
|
||||
return (self.response(data), self.status_code(), self.headers())
|
||||
|
||||
|
||||
def status_code(self):
|
||||
return 200
|
||||
|
||||
|
||||
def response(self, data):
|
||||
return json.dumps(data, default=obj_dict)
|
||||
|
||||
|
||||
|
||||
class RequestCode_HTTP_201_CREATED(RequestStatusCode):
|
||||
def __init__(self) -> None:
|
||||
@ -60,10 +60,10 @@ class RequestCode_HTTP_201_CREATED(RequestStatusCode):
|
||||
|
||||
def __call__(self, data):
|
||||
return (self.response(data), self.status_code(), self.headers())
|
||||
|
||||
|
||||
def status_code(self):
|
||||
return 201
|
||||
|
||||
|
||||
def response(self, new_id):
|
||||
return json.dumps({"id":new_id})
|
||||
|
||||
@ -74,10 +74,10 @@ class RequestCode_HTTP_400_BAD_REQUEST(RequestStatusCode):
|
||||
|
||||
def __call__(self, data):
|
||||
return (self.response(data), self.status_code(), self.headers())
|
||||
|
||||
|
||||
def status_code(self):
|
||||
return 400
|
||||
|
||||
|
||||
def response(self, data):
|
||||
return json.dumps(data)
|
||||
|
||||
@ -88,15 +88,15 @@ class RequestCode_HTTP_403_FORBIDDEN(RequestStatusCode):
|
||||
|
||||
def __call__(self, data):
|
||||
return (self.response(data), self.status_code(), self.headers())
|
||||
|
||||
|
||||
def status_code(self):
|
||||
return 403
|
||||
|
||||
|
||||
def response(self, message="invalid credentials"):
|
||||
result = {}
|
||||
result["message"] = message
|
||||
result["error_field"] = message
|
||||
return json.dumps(result)
|
||||
|
||||
|
||||
|
||||
class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
|
||||
def __init__(self) -> None:
|
||||
@ -104,13 +104,13 @@ class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
|
||||
|
||||
def __call__(self, data):
|
||||
return (self.response(data), self.status_code(), self.headers())
|
||||
|
||||
|
||||
def status_code(self):
|
||||
return 404
|
||||
|
||||
|
||||
def response(self, message="no such record"):
|
||||
result = {}
|
||||
result["message"] = message
|
||||
result["error_field"] = message
|
||||
return json.dumps(result)
|
||||
|
||||
|
||||
@ -120,12 +120,12 @@ class RequestCode_HTTP_500_INTERNAL_SERVER_ERROR(RequestStatusCode):
|
||||
|
||||
def __call__(self, data):
|
||||
return (self.response(data), self.status_code(), self.headers())
|
||||
|
||||
|
||||
def status_code(self):
|
||||
return 500
|
||||
|
||||
|
||||
def response(self, message="credential lookup mismatch"):
|
||||
result = {}
|
||||
result["message"] = message
|
||||
result["error_field"] = message
|
||||
return json.dumps(result)
|
||||
|
||||
|
||||
|
||||
@ -10,20 +10,38 @@ def create_sql_query_shipcall_get(options:dict)->str:
|
||||
options : dict. A dictionary, which must contains the 'past_days' key (int). Determines the range
|
||||
by which shipcalls are filtered.
|
||||
"""
|
||||
query = ("SELECT s.id as id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
||||
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
||||
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
||||
"evaluation_message, evaluation_time, evaluation_notifications_sent, s.created as created, s.modified as modified, time_ref_point " +
|
||||
"FROM shipcall s " +
|
||||
"LEFT JOIN times t ON t.shipcall_id = s.id AND t.participant_type = 8 " +
|
||||
"WHERE " +
|
||||
"(type = 1 AND " +
|
||||
"((t.id IS NOT NULL AND t.eta_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||
"(eta >= DATE(NOW() - INTERVAL %d DAY)))) OR " +
|
||||
"((type = 2 OR type = 3) AND " +
|
||||
"((t.id IS NOT NULL AND t.etd_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||
"(etd >= DATE(NOW() - INTERVAL %d DAY)))) " +
|
||||
"ORDER BY eta") % (options["past_days"], options["past_days"], options["past_days"], options["past_days"])
|
||||
if "participant_id" not in options: # if no participant_id is given, all shipcalls are selected
|
||||
query = ("SELECT s.id as id, ship_id, port_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
||||
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
||||
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
||||
"evaluation_message, evaluation_time, evaluation_notifications_sent, s.created as created, s.modified as modified, time_ref_point " +
|
||||
"FROM shipcall s " +
|
||||
"LEFT JOIN times t ON t.shipcall_id = s.id AND t.participant_type = 8 " +
|
||||
"WHERE " +
|
||||
"(type = 1 AND " +
|
||||
"((t.id IS NOT NULL AND t.eta_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||
"(eta >= DATE(NOW() - INTERVAL %d DAY)))) OR " +
|
||||
"((type = 2 OR type = 3) AND " +
|
||||
"((t.id IS NOT NULL AND t.etd_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||
"(etd >= DATE(NOW() - INTERVAL %d DAY)))) " +
|
||||
"ORDER BY eta") % (options["past_days"], options["past_days"], options["past_days"], options["past_days"])
|
||||
else:
|
||||
query = ("SELECT s.id as id, ship_id, port_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
||||
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
||||
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
||||
"evaluation_message, evaluation_time, evaluation_notifications_sent, s.created as created, s.modified as modified, time_ref_point " +
|
||||
"FROM shipcall s " +
|
||||
"LEFT JOIN times t ON t.shipcall_id = s.id AND t.participant_type = 8 " +
|
||||
"WHERE " +
|
||||
"port_id in (SELECT port_id FROM participant_port_map WHERE participant_id = %d)" +
|
||||
" AND (" +
|
||||
"(type = 1 AND " +
|
||||
"((t.id IS NOT NULL AND t.eta_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||
"(eta >= DATE(NOW() - INTERVAL %d DAY)))) OR " +
|
||||
"((type = 2 OR type = 3) AND " +
|
||||
"((t.id IS NOT NULL AND t.etd_berth >= DATE(NOW() - INTERVAL %d DAY)) OR " +
|
||||
"(etd >= DATE(NOW() - INTERVAL %d DAY))))) " +
|
||||
"ORDER BY eta") % (options["participant_id"], options["past_days"], options["past_days"], options["past_days"], options["past_days"])
|
||||
|
||||
return query
|
||||
|
||||
|
||||
@ -4,19 +4,33 @@ import datetime
|
||||
def get_user_data_for_id(user_id:int, expiration_time:int=90):
|
||||
"""debugging function, which is useful to pull user_data from the database, which may be used to create stub data and unit tests"""
|
||||
query = "SELECT * FROM user where id = ?id?"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":user_id})
|
||||
pdata = pdata[0] if len(pdata)>0 else None
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":user_id}, command_type="single_or_none")
|
||||
assert pdata is not None, f"could not find user with id {user_id}"
|
||||
|
||||
user_data = {k:v for k,v in pdata.items() if k in ['id','participant_id','first_name','last_name','user_name','user_phone','user_email']}
|
||||
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}"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":times_id}, command_type="single_or_none")
|
||||
return pdata
|
||||
|
||||
def get_ship_data_for_id(ship_id:int):
|
||||
"""helper function to load previous ship data from the database"""
|
||||
query = "SELECT * FROM ship where id = ?id?"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":ship_id}, command_type="single_or_none")
|
||||
return pdata
|
||||
|
||||
def get_shipcall_data_for_id(shipcall_id:int):
|
||||
"""helper function to load previous shipcall data from the database"""
|
||||
query = "SELECT * FROM shipcall where id = ?id?"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"id":shipcall_id}, command_type="single_or_none")
|
||||
return pdata
|
||||
|
||||
def get_port_ids_for_participant_id(participant_id:int):
|
||||
"""helper function to load all port ids for a participant"""
|
||||
query = "SELECT port_id FROM participant_port_map where participant_id = ?participant_id?"
|
||||
pdata = execute_sql_query_standalone(query=query, param={"participant_id":participant_id})
|
||||
return pdata
|
||||
@ -6,4 +6,5 @@ from . import times
|
||||
from . import ships
|
||||
from . import login
|
||||
from . import user
|
||||
from . import history
|
||||
from . import history
|
||||
from . import ports
|
||||
@ -4,9 +4,8 @@ import pydapper
|
||||
|
||||
from ..schemas import model
|
||||
from .. import local_db
|
||||
from BreCal.database.sql_queries import SQLQuery
|
||||
|
||||
def GetBerths(token):
|
||||
def GetBerths(options):
|
||||
"""
|
||||
No parameters, gets all entries
|
||||
"""
|
||||
@ -14,16 +13,25 @@ def GetBerths(token):
|
||||
try:
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
# query = SQLQuery.get_berth()
|
||||
# data = commands.query(query, model=model.Berth)
|
||||
data = commands.query("SELECT id, name, `lock`, owner_id, authority_id, created, modified, deleted FROM berth WHERE deleted = 0 ORDER BY name", model=model.Berth)
|
||||
|
||||
# only load berths to ports that the participant is assigned to
|
||||
if "participant_id" in options:
|
||||
query = ("SELECT id, name, `lock`, owner_id, port_id, authority_id, created, modified, deleted FROM berth WHERE " +
|
||||
"deleted = 0 AND + "
|
||||
"port_id IN (SELECT port_id FROM participant_port_map WHERE participant_id = %d) " +
|
||||
"ORDER BY name") % (options["participant_id"])
|
||||
else:
|
||||
query = ("SELECT id, name, `lock`, owner_id, port_id, authority_id, created, modified, deleted FROM berth WHERE " +
|
||||
"deleted = 0 ORDER BY name")
|
||||
|
||||
data = commands.query(query, model=model.Berth)
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500
|
||||
|
||||
finally:
|
||||
|
||||
@ -35,7 +35,7 @@ def GetHistory(options):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps("call failed"), 500
|
||||
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
@ -21,7 +21,7 @@ def GetUser(options):
|
||||
"api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, created, modified FROM user " +
|
||||
"WHERE user_name = ?username? OR user_email = ?username?",
|
||||
model=model.User, param={"username" : options["username"]})
|
||||
|
||||
|
||||
if len(data) == 1:
|
||||
if bcrypt.checkpw(options["password"].encode("utf-8"), bytes(data[0].password_hash, "utf-8")):
|
||||
result = {
|
||||
@ -39,18 +39,19 @@ def GetUser(options):
|
||||
|
||||
if len(data) > 1:
|
||||
result = {}
|
||||
result["message"] = "credential lookup mismatch"
|
||||
result["error_field"] = "credential lookup mismatch"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
result = {}
|
||||
result["message"] = "invalid credentials"
|
||||
result["error_field"] = "invalid credentials"
|
||||
return json.dumps(result), 403, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed: " + str(ex)
|
||||
result["error_field"] = "call failed"
|
||||
result["error_description"] = str(ex)
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
|
||||
@ -27,7 +27,7 @@ def GetNotifications(options):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
@ -10,7 +10,6 @@ def GetParticipant(options):
|
||||
"""
|
||||
:param options: A dictionary containing all the paramters for the Operations
|
||||
options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call.
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
@ -18,10 +17,39 @@ def GetParticipant(options):
|
||||
commands = pydapper.using(pooledConnection)
|
||||
if "user_id" in options and options["user_id"]:
|
||||
# query = SQLQuery.get_participant_by_user_id()
|
||||
data = commands.query("SELECT p.id as id, p.name as name, p.street as street, p.postal_code as postal_code, p.city as city, p.type as type, p.flags as flags, p.created as created, p.modified as modified, p.deleted as deleted FROM participant p INNER JOIN user u WHERE u.participant_id = p.id and u.id = ?userid?", model=model.Participant, param={"userid" : options["user_id"]})
|
||||
query = ("SELECT p.id as id, p.name as name, p.street as street, p.postal_code as postal_code, p.city as city, p.type as type, p.flags as flags, " +
|
||||
"p.created as created, p.modified as modified, p.deleted as deleted FROM participant p " +
|
||||
"INNER JOIN user u WHERE u.participant_id = p.id and u.id = %s") % options["user_id"]
|
||||
data = commands.query(query, model=model.Participant)
|
||||
for participant in data:
|
||||
port_query = "SELECT port_id FROM participant_port_map WHERE participant_id=?id?"
|
||||
for record in commands.query(port_query, model=model.Port_Assignment, param={"id" : participant.id}, buffered=False):
|
||||
pa = model.Port_Assignment(record.port_id)
|
||||
participant.ports.append(pa.port_id)
|
||||
else:
|
||||
# query = SQLQuery.get_participants()
|
||||
data = commands.query("SELECT id, name, street, postal_code, city, type, flags, created, modified, deleted FROM participant p ORDER BY p.name", model=model.Participant)
|
||||
if "participant_id" in options:
|
||||
# list only participants that are assigned to the same ports than participant of caller
|
||||
query = ("SELECT p.id as id, name, street, postal_code, city, type, flags, p.created, p.modified, p.deleted " +
|
||||
"FROM participant p " +
|
||||
"JOIN participant_port_map ON p.id = participant_port_map.participant_id " +
|
||||
"WHERE participant_port_map.port_id IN " +
|
||||
"(SELECT port_id FROM participant_port_map where participant_id = %s) " +
|
||||
"GROUP BY id " +
|
||||
"ORDER BY p.name") % options["participant_id"]
|
||||
else:
|
||||
query = ("SELECT p.id as id, name, street, postal_code, city, type, flags, p.created, p.modified, p.deleted " +
|
||||
"FROM participant p " +
|
||||
"JOIN participant_port_map ON p.id = participant_port_map.participant_id " +
|
||||
"GROUP BY id " +
|
||||
"ORDER BY p.name")
|
||||
|
||||
data = commands.query(query, model=model.Participant)
|
||||
for participant in data:
|
||||
port_query = "SELECT port_id FROM participant_port_map WHERE participant_id=?id?"
|
||||
for record in commands.query(port_query, model=model.Port_Assignment, param={"id" : participant.id}, buffered=False):
|
||||
pa = model.Port_Assignment(record.port_id)
|
||||
participant.ports.append(pa.port_id)
|
||||
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
@ -29,7 +57,7 @@ def GetParticipant(options):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps("call failed"), 500
|
||||
|
||||
finally:
|
||||
|
||||
33
src/server/BreCal/impl/ports.py
Normal file
33
src/server/BreCal/impl/ports.py
Normal file
@ -0,0 +1,33 @@
|
||||
import json
|
||||
import logging
|
||||
import pydapper
|
||||
|
||||
from ..schemas import model
|
||||
from .. import local_db
|
||||
from BreCal.database.sql_queries import SQLQuery
|
||||
|
||||
def GetPorts(token):
|
||||
"""
|
||||
No parameters, gets all entries
|
||||
"""
|
||||
|
||||
try:
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
data = commands.query("SELECT id, name, locode, created, modified, deleted FROM port ORDER BY name", model=model.Port)
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500
|
||||
|
||||
finally:
|
||||
if pooledConnection is not None:
|
||||
pooledConnection.close()
|
||||
|
||||
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ def GetShipcalls(options):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
@ -52,8 +52,8 @@ def GetShipcalls(options):
|
||||
|
||||
def PostShipcalls(schemaModel):
|
||||
"""
|
||||
This function *executes* a post-request for shipcalls. The function is accessible as part of an API route.
|
||||
|
||||
This function *executes* a post-request for shipcalls. The function is accessible as part of an API route.
|
||||
|
||||
The common sequence is:
|
||||
a) issue a request to the Flask API
|
||||
b) BreCal.api.shipcalls.PostShipcalls, to verify the incoming request (which includes an authentification guard)
|
||||
@ -62,8 +62,8 @@ def PostShipcalls(schemaModel):
|
||||
:param schemaModel: The deserialized dict of the request
|
||||
e.g.,
|
||||
{
|
||||
'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19),
|
||||
'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0,
|
||||
'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19),
|
||||
'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0,
|
||||
'pier_side': False, 'bunkering': True, 'recommended_tugs': 2, 'type_value': 1, 'evaluation_value': 0}
|
||||
}
|
||||
"""
|
||||
@ -151,7 +151,7 @@ def PostShipcalls(schemaModel):
|
||||
commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||
|
||||
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex, status_code=400, create_log=True)
|
||||
|
||||
@ -160,7 +160,7 @@ def PostShipcalls(schemaModel):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
@ -262,7 +262,7 @@ def PutShipcalls(schemaModel):
|
||||
commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||
|
||||
return json.dumps({"id" : schemaModel["id"]}), 200
|
||||
|
||||
|
||||
except ValidationError as ex:
|
||||
return create_validation_error_response(ex, status_code=400, create_log=True)
|
||||
|
||||
@ -271,7 +271,7 @@ def PutShipcalls(schemaModel):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
|
||||
@ -25,7 +25,7 @@ def GetShips(token):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
@ -91,7 +91,7 @@ def PostShip(schemaModel):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ def PutShip(schemaModel):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
@ -157,12 +157,12 @@ def DeleteShip(options):
|
||||
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
result = {}
|
||||
result["message"] = "no such record"
|
||||
result["error_field"] = "no such record"
|
||||
return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
@ -35,7 +35,7 @@ def GetTimes(options):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
@ -104,7 +104,7 @@ def PostTimes(schemaModel):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
@ -164,7 +164,7 @@ def PutTimes(schemaModel):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
@ -195,14 +195,14 @@ def DeleteTimes(options):
|
||||
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
result = {}
|
||||
result["message"] = "no such record"
|
||||
result["error_field"] = "no such record"
|
||||
return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
|
||||
@ -63,7 +63,7 @@ def PutUser(schemaModel):
|
||||
commands.execute(query, param={"password_hash" : password_hash, "id" : schemaModel["id"]})
|
||||
else:
|
||||
result = {}
|
||||
result["message"] = "old password invalid"
|
||||
result["error_field"] = "old password invalid"
|
||||
return json.dumps(result), 400, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
return json.dumps({"id" : schemaModel["id"]}), 200
|
||||
@ -72,7 +72,7 @@ def PutUser(schemaModel):
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
result["error_field"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
finally:
|
||||
|
||||
@ -29,6 +29,16 @@ class Berth(Schema):
|
||||
lock: bool
|
||||
owner_id: int
|
||||
authority_id: int
|
||||
port_id: int
|
||||
created: datetime
|
||||
modified: datetime
|
||||
deleted: bool
|
||||
|
||||
@dataclass
|
||||
class Port(Schema):
|
||||
id: int
|
||||
name: str
|
||||
locode: str
|
||||
created: datetime
|
||||
modified: datetime
|
||||
deleted: bool
|
||||
@ -54,7 +64,7 @@ class EvaluationType(IntEnum):
|
||||
def _missing_(cls, value):
|
||||
return cls.undefined
|
||||
|
||||
class NotificationType(IntEnum):
|
||||
class NotificationType(IntEnum):
|
||||
"""
|
||||
Any user has the attributes
|
||||
'notify_email' -> NotificationType.email
|
||||
@ -67,7 +77,7 @@ class NotificationType(IntEnum):
|
||||
push = 2
|
||||
# whatsapp = 3
|
||||
# signal = 4
|
||||
|
||||
|
||||
@classmethod
|
||||
def _missing_(cls, value):
|
||||
return cls.undefined
|
||||
@ -128,7 +138,7 @@ class GetVerifyInlineResp(Schema):
|
||||
@dataclass
|
||||
class Notification:
|
||||
"""
|
||||
Base data class for any notification.
|
||||
Base data class for any notification.
|
||||
|
||||
Description:
|
||||
'An entry corresponds to an alarm given by a violated rule during times update'
|
||||
@ -168,6 +178,7 @@ class Participant(Schema):
|
||||
created: datetime
|
||||
modified: datetime
|
||||
deleted: bool
|
||||
ports: List[int] = field(default_factory=list)
|
||||
|
||||
@validates("type")
|
||||
def validate_type(self, value):
|
||||
@ -175,7 +186,7 @@ class Participant(Schema):
|
||||
max_int = sum([int(val) for val in list(ParticipantType._value2member_map_.values())])
|
||||
min_int = 0
|
||||
|
||||
valid_type = 0 <= value < max_int
|
||||
valid_type = 0 <= value < max_int
|
||||
if not valid_type:
|
||||
raise ValidationError({"type":f"the provided integer is not supported for default behaviour of the ParticipantType IntFlag. Your choice: {value}. Supported values are: 0 <= value {max_int}"})
|
||||
|
||||
@ -186,7 +197,7 @@ class Participant(Schema):
|
||||
max_int = sum([int(val) for val in list(ParticipantFlag._value2member_map_.values())])
|
||||
min_int = 0
|
||||
|
||||
valid_type = 0 <= value < max_int
|
||||
valid_type = 0 <= value < max_int
|
||||
if not valid_type:
|
||||
raise ValidationError({"flags":f"the provided integer is not supported for default behaviour of the ParticipantFlag IntFlag. Your choice: {value}. Supported values are: 0 <= value {max_int}"})
|
||||
|
||||
@ -205,6 +216,7 @@ class ShipcallSchema(Schema):
|
||||
|
||||
id = fields.Integer(required=True)
|
||||
ship_id = fields.Integer(required=True)
|
||||
port_id = fields.Integer(required=True)
|
||||
type = fields.Enum(ShipcallType, default=ShipcallType.undefined)
|
||||
eta = fields.DateTime(required=False, allow_none=True)
|
||||
voyage = fields.String(allow_none=True, required=False, validate=[validate.Length(max=16)])
|
||||
@ -243,15 +255,15 @@ class ShipcallSchema(Schema):
|
||||
data['type_value'] = int(ShipcallType.undefined)
|
||||
if 'evaluation' in data:
|
||||
if data['evaluation']:
|
||||
data['evaluation_value'] = int(data['evaluation'])
|
||||
data['evaluation_value'] = int(data['evaluation'])
|
||||
else:
|
||||
data['evaluation_value'] = int(EvaluationType.undefined)
|
||||
return data
|
||||
|
||||
|
||||
@validates("type")
|
||||
def validate_type(self, value):
|
||||
valid_shipcall_type = int(value) in [item.value for item in ShipcallType]
|
||||
|
||||
|
||||
if not valid_shipcall_type:
|
||||
raise ValidationError({"type":f"the provided type is not a valid shipcall type."})
|
||||
|
||||
@ -269,6 +281,16 @@ class Participant_Assignment:
|
||||
def to_json(self):
|
||||
return self.__dict__
|
||||
|
||||
@dataclass
|
||||
class Port_Assignment:
|
||||
def __init__(self, port_id):
|
||||
self.port_id = port_id
|
||||
pass
|
||||
|
||||
port_id: int
|
||||
|
||||
def to_json(self):
|
||||
return self.__dict__
|
||||
|
||||
@dataclass
|
||||
class Shipcall:
|
||||
@ -301,6 +323,7 @@ class Shipcall:
|
||||
evaluation_time: datetime
|
||||
evaluation_notifications_sent: bool
|
||||
time_ref_point: int
|
||||
port_id: int
|
||||
created: datetime
|
||||
modified: datetime
|
||||
participants: List[Participant_Assignment] = field(default_factory=list)
|
||||
@ -335,6 +358,7 @@ class Shipcall:
|
||||
"evaluation_time": self.evaluation_time.isoformat() if self.evaluation_time else "",
|
||||
"evaluation_notifications_sent": self.evaluation_notifications_sent,
|
||||
"time_ref_point": self.time_ref_point,
|
||||
"port_id": self.port_id,
|
||||
"created": self.created.isoformat() if self.created else "",
|
||||
"modified": self.modified.isoformat() if self.modified else "",
|
||||
"participants": [participant.__dict__ for participant in self.participants]
|
||||
@ -343,8 +367,8 @@ class Shipcall:
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_query_row(self, id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, evaluation_message, evaluation_time, evaluation_notifications_sent, time_ref_point, created, modified):
|
||||
return self(id, ship_id, ShipcallType(type), eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, EvaluationType(evaluation), evaluation_message, evaluation_time, evaluation_notifications_sent, time_ref_point, created, modified)
|
||||
def from_query_row(self, id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, evaluation_message, evaluation_time, evaluation_notifications_sent, time_ref_point, port_id, created, modified):
|
||||
return self(id, ship_id, ShipcallType(type), eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, EvaluationType(evaluation), evaluation_message, evaluation_time, evaluation_notifications_sent, time_ref_point, port_id, created, modified)
|
||||
|
||||
class ShipcallId(Schema):
|
||||
pass
|
||||
@ -436,7 +460,7 @@ class TimesSchema(Schema):
|
||||
# when 'value' is 'None', a ValidationError is not issued.
|
||||
valid_time = validate_time_is_in_not_too_distant_future(raise_validation_error=True, value=value, months=12)
|
||||
return
|
||||
|
||||
|
||||
@validates("eta_interval_end")
|
||||
def validate_eta_interval_end(self, value):
|
||||
# violation when time is not in the future, but also does not exceed a threshold for the 'reasonable' future
|
||||
@ -472,12 +496,12 @@ class UserSchema(Schema):
|
||||
valid_characters = list(map(str,range(0,10)))+["+", " "]
|
||||
if not all([v in valid_characters for v in value]):
|
||||
raise ValidationError({"user_phone":f"one of the phone number values is not valid."})
|
||||
|
||||
|
||||
@validates("user_email")
|
||||
def validate_user_email(self, value):
|
||||
if not "@" in value:
|
||||
raise ValidationError({"user_email":f"invalid email address"})
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class Times:
|
||||
@ -568,7 +592,7 @@ class ShipSchema(Schema):
|
||||
raise ValidationError({"name":f"'name' argument should have at least one character"})
|
||||
elif character_length>=64:
|
||||
raise ValidationError({"name":f"'name' argument should have at max. 63 characters"})
|
||||
|
||||
|
||||
if check_if_string_has_special_characters(value):
|
||||
raise ValidationError({"name":f"'name' argument should not have special characters."})
|
||||
return
|
||||
@ -587,7 +611,7 @@ class ShipSchema(Schema):
|
||||
callsign_length = len(str(value))
|
||||
if callsign_length>8:
|
||||
raise ValidationError({"callsign":f"'callsign' argument should not have more than 8 characters"})
|
||||
|
||||
|
||||
if check_if_string_has_special_characters(value):
|
||||
raise ValidationError({"callsign":f"'callsign' argument should not have special characters."})
|
||||
return
|
||||
|
||||
@ -25,9 +25,9 @@ def auth_guard(role=None):
|
||||
try:
|
||||
user_data = check_jwt()
|
||||
except Exception as e:
|
||||
return json.dumps({"message" : f'{e}', "status": 401}), 401
|
||||
return json.dumps({"error_field" : f'{e}', "status": 401}), 401
|
||||
if role and role not in user_data['roles']:
|
||||
return json.dumps({"message": 'Authorization required.', "status" : 403}), 403
|
||||
return json.dumps({"error_field": 'Authorization required.', "status" : 403}), 403
|
||||
# get on to original route
|
||||
return route_function(*args, **kwargs)
|
||||
decorated_function.__name__ = route_function.__name__
|
||||
|
||||
@ -8,6 +8,7 @@ from string import ascii_letters, digits
|
||||
from BreCal.schemas.model import Ship, Shipcall, Berth, User, Participant, ShipcallType
|
||||
from BreCal.database.sql_handler import execute_sql_query_standalone
|
||||
from BreCal.database.sql_queries import SQLQuery
|
||||
from BreCal.database.sql_utils import get_ship_data_for_id
|
||||
from BreCal.impl.participant import GetParticipant
|
||||
from BreCal.impl.ships import GetShips
|
||||
from BreCal.impl.berths import GetBerths
|
||||
@ -17,6 +18,7 @@ from BreCal.validators.input_validation_utils import check_if_user_is_bsmd_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
|
||||
|
||||
import werkzeug
|
||||
|
||||
class InputValidationShip():
|
||||
@ -32,6 +34,17 @@ class InputValidationShip():
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def exists_ship_by_dict(model:dict):
|
||||
ship_id = model.get("id")
|
||||
if(ship_id is not None):
|
||||
return get_ship_data_for_id(ship_id) is not None
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def exists_ship_by_id(id:int):
|
||||
return get_ship_data_for_id(id) is not None
|
||||
|
||||
@staticmethod
|
||||
def evaluate_post_data(user_data:dict, loadedModel:dict, content:dict):
|
||||
# 1.) Only users of type BSMD are allowed to POST
|
||||
|
||||
@ -11,6 +11,7 @@ from BreCal.impl.ships import GetShips
|
||||
from BreCal.impl.berths import GetBerths
|
||||
|
||||
from BreCal.database.enums import ParticipantType, ParticipantFlag
|
||||
from BreCal.database.sql_utils import get_shipcall_data_for_id
|
||||
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
|
||||
@ -98,6 +99,10 @@ class InputValidationShipcall():
|
||||
InputValidationShipcall.check_shipcall_is_canceled(loadedModel, content)
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def exists_shipcall_by_id(id:int):
|
||||
return get_shipcall_data_for_id(id) is not None
|
||||
|
||||
@staticmethod
|
||||
def check_shipcall_values(loadedModel:dict, content:dict, forbidden_keys:list=["evaluation", "evaluation_message"], is_put_data:bool=False):
|
||||
"""
|
||||
@ -235,21 +240,22 @@ class InputValidationShipcall():
|
||||
ship_id = loadedModel.get("ship_id", None)
|
||||
arrival_berth_id = loadedModel.get("arrival_berth_id", None)
|
||||
departure_berth_id = loadedModel.get("departure_berth_id", None)
|
||||
port_id = loadedModel.get("port_id", None)
|
||||
participants = loadedModel.get("participants",[])
|
||||
|
||||
valid_ship_id = check_if_ship_id_is_valid(ship_id=ship_id)
|
||||
if not valid_ship_id:
|
||||
raise ValidationError({"ship_id":f"provided an invalid ship id, which is not found in the database: {ship_id}"})
|
||||
|
||||
valid_arrival_berth_id = check_if_berth_id_is_valid(berth_id=arrival_berth_id)
|
||||
valid_arrival_berth_id = check_if_berth_id_is_valid(berth_id=arrival_berth_id, port_id=port_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: {arrival_berth_id}"})
|
||||
raise ValidationError({"arrival_berth_id":f"provided an invalid arrival berth id, which is not found in the database: {arrival_berth_id}, or the berth is not assigned to the port: {port_id}"})
|
||||
|
||||
valid_departure_berth_id = check_if_berth_id_is_valid(berth_id=departure_berth_id)
|
||||
valid_departure_berth_id = check_if_berth_id_is_valid(berth_id=departure_berth_id, port_id=port_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: {departure_berth_id}"})
|
||||
raise ValidationError({"departure_berth_id":f"provided an invalid departure berth id, which is not found in the database: {departure_berth_id}, or the berth is not assigned to the port: {port_id}"})
|
||||
|
||||
valid_participant_ids = check_if_participant_ids_are_valid(participants=participants)
|
||||
valid_participant_ids = check_if_participant_ids_are_valid(participants=participants, port_id=port_id)
|
||||
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: {participants}"})
|
||||
|
||||
@ -332,7 +338,7 @@ class InputValidationShipcall():
|
||||
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
|
||||
Performs datetime checks in the loadedModel (datetime.datetime objects).
|
||||
Perfornms datetime checks in the loadedModel (datetime.datetime objects).
|
||||
"""
|
||||
# obtain the current datetime to check, whether the provided values are after ref time
|
||||
time_ref = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||
@ -445,15 +451,16 @@ class InputValidationShipcall():
|
||||
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_ref:
|
||||
raise ValidationError({"tidal_window_to":f"'tidal_window_to' is too far in the past. Incorrect datetime provided."})
|
||||
raise ValidationError({"tidal_window_to":f"'tidal_window_to' must be in the future. 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_ref:
|
||||
raise ValidationError({"tidal_window_from":f"'tidal_window_from' is too far in the past. Incorrect datetime provided."})
|
||||
raise ValidationError({"tidal_window_from":f"'tidal_window_from' must be in the future. 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}."})
|
||||
|
||||
@ -491,7 +498,7 @@ class InputValidationShipcall():
|
||||
|
||||
# if the *existing* shipcall in the database is canceled, it may not be changed
|
||||
if shipcall.get("canceled", False):
|
||||
raise ValidationError({"canceled":f"The shipcall with id 'shipcall_id' is canceled. A canceled shipcall may not be changed."})
|
||||
raise ValidationError({"canceled":f"The shipcall with id {shipcall_id} is canceled. A canceled shipcall may not be changed."})
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
|
||||
@ -128,6 +128,10 @@ class InputValidationTimes():
|
||||
InputValidationTimes.check_user_belongs_to_same_group_as_dataset_determines(user_data, loadedModel=None, times_id=times_id)
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def exists_times_by_id(id:int):
|
||||
return get_times_data_for_id(id) is not None
|
||||
|
||||
@staticmethod
|
||||
def check_if_entry_is_already_deleted(times_id:int):
|
||||
"""
|
||||
@ -195,10 +199,11 @@ class InputValidationTimes():
|
||||
"""
|
||||
# extract the IDs
|
||||
berth_id, shipcall_id, participant_id = content.get("berth_id"), content.get("shipcall_id"), content.get("participant_id")
|
||||
port_id = content.get("port_id", None)
|
||||
|
||||
valid_berth_id_reference = check_if_berth_id_is_valid(berth_id)
|
||||
valid_berth_id_reference = check_if_berth_id_is_valid(berth_id, port_id)
|
||||
if not valid_berth_id_reference:
|
||||
raise ValidationError({"berth_id":f"The referenced berth_id '{berth_id}' does not exist in the database."})
|
||||
raise ValidationError({"berth_id":f"The referenced berth_id '{berth_id}' does not exist in the database or is not assigned to the port '{port_id}'."})
|
||||
|
||||
valid_shipcall_id_reference = check_if_shipcall_id_is_valid(shipcall_id)
|
||||
if not valid_shipcall_id_reference:
|
||||
|
||||
@ -8,12 +8,13 @@ from BreCal.impl.berths import GetBerths
|
||||
from BreCal.impl.shipcalls import GetShipcalls
|
||||
|
||||
from BreCal.database.enums import ParticipantType
|
||||
from BreCal.database.sql_utils import get_port_ids_for_participant_id
|
||||
from marshmallow import ValidationError
|
||||
|
||||
def get_participant_id_dictionary():
|
||||
"""
|
||||
get a dictionary of all participants, where the key is the participant's id, and the value is a dictionary
|
||||
of common participant data (not a data model).
|
||||
of common participant data (not a data model).
|
||||
"""
|
||||
# get all participants
|
||||
response,status_code,header = GetParticipant(options={})
|
||||
@ -26,7 +27,7 @@ def get_participant_id_dictionary():
|
||||
|
||||
def get_berth_id_dictionary():
|
||||
# get all berths
|
||||
response,status_code,header = GetBerths(token=None)
|
||||
response,status_code,header = GetBerths(options={})
|
||||
|
||||
# build a dictionary of id:item pairs, so one can select the respective participant
|
||||
berths = json.loads(response)
|
||||
@ -72,7 +73,7 @@ def check_if_user_is_bsmd_type(user_data:dict)->bool:
|
||||
given a dictionary of user data, determine the respective participant id and read, whether
|
||||
that participant is a .BSMD-type
|
||||
|
||||
Note: ParticipantType is an IntFlag.
|
||||
Note: ParticipantType is an IntFlag.
|
||||
Hence, ParticipantType(1) is ParticipantType.BSMD,
|
||||
and ParticipantType(7) is [ParticipantType.BSMD, ParticipantType.TERMINAL, ParticipantType.PILOT]
|
||||
|
||||
@ -84,7 +85,7 @@ def check_if_user_is_bsmd_type(user_data:dict)->bool:
|
||||
participant_type = get_participant_type_from_user_data(user_data)
|
||||
|
||||
# boolean check: is the participant of type .BSMD?
|
||||
is_bsmd = ParticipantType.BSMD in participant_type
|
||||
is_bsmd = ParticipantType.BSMD in participant_type
|
||||
return is_bsmd
|
||||
|
||||
def check_if_user_has_bsmd_flag(user_data:dict)->bool:
|
||||
@ -92,7 +93,7 @@ def check_if_user_has_bsmd_flag(user_data:dict)->bool:
|
||||
given a dictionary of user data, determine the respective participant id and read, whether
|
||||
that participant is a .BSMD-type
|
||||
|
||||
Note: ParticipantType is an IntFlag.
|
||||
Note: ParticipantType is an IntFlag.
|
||||
Hence, ParticipantType(1) is ParticipantType.BSMD,
|
||||
and ParticipantType(7) is [ParticipantType.BSMD, ParticipantType.TERMINAL, ParticipantType.PILOT]
|
||||
|
||||
@ -104,7 +105,7 @@ def check_if_user_has_bsmd_flag(user_data:dict)->bool:
|
||||
participant_type = get_participant_type_from_user_data(user_data)
|
||||
|
||||
# boolean check: is the participant of type .BSMD?
|
||||
is_bsmd = ParticipantType.BSMD in participant_type
|
||||
is_bsmd = ParticipantType.BSMD in participant_type
|
||||
return is_bsmd
|
||||
|
||||
|
||||
@ -112,31 +113,37 @@ def check_if_ship_id_is_valid(ship_id):
|
||||
"""check, whether the provided ID is valid. If it is 'None', it will be considered valid. This is, because a shipcall POST-request, does not have to include all IDs at once"""
|
||||
if ship_id is None:
|
||||
return True
|
||||
|
||||
|
||||
# build a dictionary of id:item pairs, so one can select the respective participant
|
||||
ships = get_ship_id_dictionary()
|
||||
|
||||
|
||||
# boolean check
|
||||
ship_id_is_valid = ship_id in list(ships.keys())
|
||||
return ship_id_is_valid
|
||||
|
||||
def check_if_berth_id_is_valid(berth_id):
|
||||
def check_if_berth_id_is_valid(berth_id, port_id=None):
|
||||
"""check, whether the provided ID is valid. If it is 'None', it will be considered valid. This is, because a shipcall POST-request, does not have to include all IDs at once"""
|
||||
if berth_id is None:
|
||||
return True
|
||||
|
||||
|
||||
# build a dictionary of id:item pairs, so one can select the respective participant
|
||||
berths = get_berth_id_dictionary()
|
||||
|
||||
# boolean check
|
||||
berth_id_is_valid = berth_id in list(berths.keys())
|
||||
|
||||
if port_id is not None:
|
||||
# check, whether the berth is assigned to the respective port
|
||||
berth_is_assigned_to_port = berths.get(berth_id,{}).get("port_id") == port_id
|
||||
berth_id_is_valid = berth_id_is_valid and berth_is_assigned_to_port
|
||||
|
||||
return berth_id_is_valid
|
||||
|
||||
def check_if_shipcall_id_is_valid(shipcall_id:int):
|
||||
"""check, whether the provided ID is valid. If it is 'None', it will be considered valid. This is, because a request, may not have to include all IDs at once"""
|
||||
if shipcall_id is None:
|
||||
return True
|
||||
|
||||
|
||||
# build a dictionary of id:item pairs, so one can select the respective participant
|
||||
shipcalls = get_shipcall_id_dictionary()
|
||||
|
||||
@ -149,7 +156,7 @@ def check_if_participant_id_is_valid_standalone(participant_id:int, participant_
|
||||
"""check, whether the provided ID is valid. If it is 'None', it will be considered valid. This is, because a request, may not have to include all IDs at once"""
|
||||
if participant_id is None:
|
||||
return True
|
||||
|
||||
|
||||
# build a dictionary of id:item pairs, so one can select the respective participant
|
||||
participants = get_participant_id_dictionary()
|
||||
|
||||
@ -173,10 +180,10 @@ def check_if_participant_id_is_valid_standalone(participant_id:int, participant_
|
||||
# when the participant_type is not provided, only evaluate the ID
|
||||
return participant_id_is_valid
|
||||
|
||||
def check_if_participant_id_is_valid(participant:dict):
|
||||
def check_if_participant_id_is_valid(participant:dict, port_id=None):
|
||||
"""
|
||||
check, whether the provided ID is valid. If it is 'None', it will be considered valid. This is, because a shipcall POST-request, does not have to include all IDs at once
|
||||
|
||||
|
||||
Following the common BreCal.schemas.model.ParticipantAssignmentSchema, a participant dictionary contains the keys:
|
||||
'participant_id' : int
|
||||
'type' : ParticipantType
|
||||
@ -185,9 +192,14 @@ def check_if_participant_id_is_valid(participant:dict):
|
||||
participant_id = participant.get("participant_id", None)
|
||||
participant_type = ParticipantType(int(participant.get("type", ParticipantType.undefined)))
|
||||
participant_id_is_valid = check_if_participant_id_is_valid_standalone(participant_id, participant_type)
|
||||
if participant_id_is_valid and port_id is not None:
|
||||
# check, whether the participant is assigned to the respective port
|
||||
participant_is_assigned_to_port = any(p.get('port_id', None) == port_id for p in get_port_ids_for_participant_id(participant_id))
|
||||
participant_id_is_valid &= participant_is_assigned_to_port
|
||||
|
||||
return participant_id_is_valid
|
||||
|
||||
def check_if_participant_ids_are_valid(participants:list[dict]):
|
||||
def check_if_participant_ids_are_valid(participants:list[dict], port_id=None):
|
||||
"""
|
||||
|
||||
args:
|
||||
@ -199,9 +211,9 @@ def check_if_participant_ids_are_valid(participants:list[dict]):
|
||||
# empty list -> invalid
|
||||
if participants is None:
|
||||
return False
|
||||
|
||||
|
||||
# check each participant id individually
|
||||
valid_participant_ids = [check_if_participant_id_is_valid(participant) for participant in participants]
|
||||
valid_participant_ids = [check_if_participant_id_is_valid(participant, port_id) for participant in participants]
|
||||
|
||||
# boolean check, whether all participant ids are valid
|
||||
return all(valid_participant_ids)
|
||||
|
||||
@ -77,7 +77,7 @@ def create_werkzeug_error_response(ex:Forbidden, status_code:int=403, create_log
|
||||
def create_dynamic_exception_response(ex, status_code:int=400, message:typing.Optional[str]=None, create_log:bool=True):
|
||||
message = repr(ex) if message is None else message
|
||||
json_response = create_default_json_response_format(error_field="Exception", error_description=message)
|
||||
json_response["message"] = "call failed"
|
||||
json_response["error_field"] = "call failed"
|
||||
|
||||
serialized_response = json.dumps(json_response, default=str)
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ from setuptools import find_packages, setup
|
||||
|
||||
setup(
|
||||
name='BreCal',
|
||||
version='1.5.0',
|
||||
version='1.6.0',
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
|
||||
Reference in New Issue
Block a user