Merge branch 'release/1.1.6'

This commit is contained in:
Daniel Schick 2024-03-13 18:15:59 +01:00
commit f9c664fbc0
19 changed files with 153 additions and 79 deletions

View File

@ -1 +1 @@
1.1.5.0 1.1.6.0

View File

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BreCalClient" xmlns:local="clr-namespace:BreCalClient"
StartupUri="MainWindow.xaml" Exit="Application_Exit"> StartupUri="MainWindow.xaml" Exit="Application_Exit" Startup="Application_Startup" >
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>

View File

@ -1,4 +1,5 @@
using BreCalClient.misc.Model; using BreCalClient.misc.Model;
using BreCalClient.Properties;
using System.Windows; using System.Windows;
namespace BreCalClient namespace BreCalClient
@ -14,5 +15,20 @@ namespace BreCalClient
{ {
BreCalClient.Properties.Settings.Default.Save(); BreCalClient.Properties.Settings.Default.Save();
} }
private void Application_Startup(object sender, StartupEventArgs e)
{
// Window size sanity check
if(Settings.Default.Width == 0)
{
Settings.Default.Width = 800;
Settings.Default.Save();
}
if(Settings.Default.Height == 0)
{
Settings.Default.Height = 450;
Settings.Default.Save();
}
}
} }
} }

View File

@ -8,8 +8,8 @@
<SignAssembly>True</SignAssembly> <SignAssembly>True</SignAssembly>
<StartupObject>BreCalClient.App</StartupObject> <StartupObject>BreCalClient.App</StartupObject>
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
<AssemblyVersion>1.1.5.0</AssemblyVersion> <AssemblyVersion>1.1.6.0</AssemblyVersion>
<FileVersion>1.1.5.0</FileVersion> <FileVersion>1.1.6.0</FileVersion>
<Title>Bremen calling client</Title> <Title>Bremen calling client</Title>
<Description>A Windows WPF client for the Bremen calling API.</Description> <Description>A Windows WPF client for the Bremen calling API.</Description>
<ApplicationIcon>containership.ico</ApplicationIcon> <ApplicationIcon>containership.ico</ApplicationIcon>

View File

@ -46,7 +46,7 @@
<Label Content="ETA" Grid.Column="2" Grid.Row="2" HorizontalContentAlignment="Right"/> <Label Content="ETA" Grid.Column="2" Grid.Row="2" HorizontalContentAlignment="Right"/>
<Label Content="ETD" Grid.Column="2" Grid.Row="3" HorizontalContentAlignment="Right"/> <Label Content="ETD" Grid.Column="2" Grid.Row="3" HorizontalContentAlignment="Right"/>
<ComboBox x:Name="comboBoxCategories" Grid.Column="3" Margin="2" Grid.Row="0" SelectedValuePath="Key" SelectionChanged="comboBoxCategories_SelectionChanged"/> <ComboBox x:Name="comboBoxCategories" Grid.Column="3" Margin="2" Grid.Row="0" SelectionChanged="comboBoxCategories_SelectionChanged"/>
<Label Content="{x:Static p:Resources.textBerth}" Grid.Column="2" Grid.Row="1" HorizontalContentAlignment="Right"/> <Label Content="{x:Static p:Resources.textBerth}" Grid.Column="2" Grid.Row="1" HorizontalContentAlignment="Right"/>
<Grid Grid.Row="1" Grid.Column="3"> <Grid Grid.Row="1" Grid.Column="3">

View File

@ -19,6 +19,10 @@ using static BreCalClient.Extensions;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Security.Principal; using System.Security.Principal;
using Polly;
using System.Net.Http;
using System.Net;
using Polly.Retry;
namespace BreCalClient namespace BreCalClient
{ {
@ -34,8 +38,7 @@ namespace BreCalClient
#region Fields #region Fields
private static Int32 _uiUpdateRunning = 0; private static Int32 _uiUpdateRunning = 0;
private Timer? _timer;
private Credentials? _credentials; private Credentials? _credentials;
private readonly ConcurrentDictionary<int, ShipcallControlModel> _allShipcallsDict = new(); private readonly ConcurrentDictionary<int, ShipcallControlModel> _allShipcallsDict = new();
@ -73,7 +76,29 @@ namespace BreCalClient
{ {
InitializeComponent(); InitializeComponent();
_api = new DefaultApi(Properties.Settings.Default.API_URL); _api = new DefaultApi(Properties.Settings.Default.API_URL);
_api.Configuration.ApiKeyPrefix["Authorization"] = "Bearer"; _api.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
const int maxDelayInMilliseconds = 32 * 1000;
var jitterer = new Random();
var retryPolicy =
Policy.Handle<HttpRequestException>()
.OrResult<RestSharp.RestResponse>(resp => resp.StatusCode == HttpStatusCode.Unauthorized)
.WaitAndRetryAsync(3,
retryAttempt =>
{
var calculatedDelayInMilliseconds = Math.Pow(2, retryAttempt) * 1000;
var jitterInMilliseconds = jitterer.Next(0, 1000);
var actualDelay = Math.Min(calculatedDelayInMilliseconds + jitterInMilliseconds, maxDelayInMilliseconds);
return TimeSpan.FromMilliseconds(actualDelay);
},
onRetry: (resp, timespan, context) =>
{
this.RefreshToken(null);
Trace.WriteLine("token refreshed");
});
RetryConfiguration.AsyncRetryPolicy = retryPolicy;
} }
#endregion #endregion
@ -123,8 +148,7 @@ namespace BreCalClient
this.busyIndicator.IsBusy = false; this.busyIndicator.IsBusy = false;
this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token; this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token;
this.LoadStaticLists(); this.LoadStaticLists();
this.labelUsername.Text = $"{_loginResult.FirstName} {_loginResult.LastName}"; this.labelUsername.Text = $"{_loginResult.FirstName} {_loginResult.LastName}";
_timer = new Timer(RefreshToken, null, 4000000, Timeout.Infinite);
} }
} }
labelGeneralStatus.Text = $"Connection {ConnectionStatus.SUCCESSFUL}"; labelGeneralStatus.Text = $"Connection {ConnectionStatus.SUCCESSFUL}";
@ -150,8 +174,9 @@ namespace BreCalClient
} }
} }
private void RefreshToken(object? state) private bool RefreshToken(object? state)
{ {
bool result = false;
try try
{ {
_loginResult = _api.LoginPost(_credentials); _loginResult = _api.LoginPost(_credentials);
@ -159,7 +184,8 @@ namespace BreCalClient
{ {
if (_loginResult.Id > 0) if (_loginResult.Id > 0)
{ {
this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token; this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token;
result = true;
} }
} }
else else
@ -171,6 +197,7 @@ namespace BreCalClient
{ {
_log.ErrorFormat("Error refreshing token: {0}", ex.Message); _log.ErrorFormat("Error refreshing token: {0}", ex.Message);
} }
return result;
} }
private void buttonExit_Click(object sender, RoutedEventArgs e) private void buttonExit_Click(object sender, RoutedEventArgs e)
@ -805,10 +832,13 @@ namespace BreCalClient
private void ShowErrorDialog(string message, string caption) private void ShowErrorDialog(string message, string caption)
{ {
_log.ErrorFormat("{0} - {1}", caption, message);
/*
Dispatcher.Invoke(new Action(() => Dispatcher.Invoke(new Action(() =>
{ {
MessageBox.Show(message, caption, MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(message, caption, MessageBoxButton.OK, MessageBoxImage.Error);
})); }));
*/
} }
private void EnableControlsForParticipant() private void EnableControlsForParticipant()

View File

@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<ApplicationRevision>0</ApplicationRevision> <ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.1.5.*</ApplicationVersion> <ApplicationVersion>1.1.6.0</ApplicationVersion>
<BootstrapperEnabled>False</BootstrapperEnabled> <BootstrapperEnabled>False</BootstrapperEnabled>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<CreateWebPageOnPublish>True</CreateWebPageOnPublish> <CreateWebPageOnPublish>True</CreateWebPageOnPublish>
@ -39,7 +39,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<SuiteName>Bremen calling client</SuiteName> <SuiteName>Bremen calling client</SuiteName>
<SupportUrl>https://www.bsmd-emswe.eu/</SupportUrl> <SupportUrl>https://www.bsmd-emswe.eu/</SupportUrl>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SkipPublishVerification>false</SkipPublishVerification>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PublishFile Include="containership.ico"> <PublishFile Include="containership.ico">

View File

@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<ApplicationRevision>0</ApplicationRevision> <ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.1.5.*</ApplicationVersion> <ApplicationVersion>1.1.6.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled> <BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<CreateDesktopShortcut>True</CreateDesktopShortcut> <CreateDesktopShortcut>True</CreateDesktopShortcut>

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
Version 2.0 Version 2.0
The primary goals of this format is to allow a simple XML format The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes various data types are done through the TypeConverter classes
associated with the data types. associated with the data types.
Example: Example:
... ado.net/XML headers & schema ... ... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader> <resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader> <resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment> <comment>This is a comment</comment>
</data> </data>
There are any number of "resheader" rows that contain simple There are any number of "resheader" rows that contain simple
name/value pairs. name/value pairs.
Each data row contains a name, and value. The row also contains a Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture. text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the Classes that don't support this are serialized and stored with the
mimetype set. mimetype set.
The mimetype is used for serialized objects, and tells the The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly: extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below. read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64 mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64 mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64 mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
--> -->
@ -284,10 +284,10 @@
<value>Neues Passwort wiederholen</value> <value>Neues Passwort wiederholen</value>
</data> </data>
<data name="textReplenishingLock" xml:space="preserve"> <data name="textReplenishingLock" xml:space="preserve">
<value>Versorgungsaufnahme Schleuse</value> <value>Güterübernahme in der Schleuse geplant</value>
</data> </data>
<data name="textReplenishingTerminal" xml:space="preserve"> <data name="textReplenishingTerminal" xml:space="preserve">
<value>Versorgungsaufnahme Terminal</value> <value>Güterübernahme am Terminal geplant</value>
</data> </data>
<data name="textRotated" xml:space="preserve"> <data name="textRotated" xml:space="preserve">
<value>Gedreht</value> <value>Gedreht</value>

View File

@ -8,7 +8,7 @@
<applicationSettings> <applicationSettings>
<RoleEditor.Properties.Settings> <RoleEditor.Properties.Settings>
<setting name="ConnectionString" serializeAs="String"> <setting name="ConnectionString" serializeAs="String">
<value>Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_devel;Port=33306</value> <value>Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling;Port=33306</value>
</setting> </setting>
</RoleEditor.Properties.Settings> </RoleEditor.Properties.Settings>
</applicationSettings> </applicationSettings>

View File

@ -17,7 +17,7 @@ def GetShipcalls():
token = request.headers.get('Authorization') token = request.headers.get('Authorization')
options = {} options = {}
options["participant_id"] = request.args.get("participant_id") options["participant_id"] = request.args.get("participant_id")
options["past_days"] = request.args.get("past_days", default=2, type=int) options["past_days"] = request.args.get("past_days", default=1, type=int)
return impl.shipcalls.GetShipcalls(options) return impl.shipcalls.GetShipcalls(options)
else: else:

View File

@ -16,7 +16,7 @@ def GetBerths(token):
pooledConnection = local_db.getPoolConnection() pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection) commands = pydapper.using(pooledConnection)
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) 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)
pooledConnection.close() return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex: except Exception as ex:
logging.error(ex) logging.error(ex)
@ -25,7 +25,9 @@ def GetBerths(token):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500 return json.dumps(result), 500
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} finally:
if pooledConnection is not None:
pooledConnection.close()

View File

@ -16,7 +16,6 @@ def GetUser(options):
commands = pydapper.using(pooledConnection) commands = pydapper.using(pooledConnection)
data = commands.query("SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, api_key, created, modified FROM user WHERE user_name = ?username? OR user_email = ?username?", data = commands.query("SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, api_key, created, modified FROM user WHERE user_name = ?username? OR user_email = ?username?",
model=model.User, param={"username" : options["username"]}) model=model.User, param={"username" : options["username"]})
pooledConnection.close()
# print(data) # print(data)
if len(data) == 1: if len(data) == 1:
if bcrypt.checkpw(options["password"].encode("utf-8"), bytes(data[0].password_hash, "utf-8")): if bcrypt.checkpw(options["password"].encode("utf-8"), bytes(data[0].password_hash, "utf-8")):
@ -49,6 +48,10 @@ def GetUser(options):
result["message"] = "call failed: " + str(ex) result["message"] = "call failed: " + str(ex)
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
if pooledConnection is not None:
pooledConnection.close()
# $2b$12$uWLE0r32IrtCV30WkMbVwOdltgeibymZyYAf4ZnQb2Bip8hrkGGwG # $2b$12$uWLE0r32IrtCV30WkMbVwOdltgeibymZyYAf4ZnQb2Bip8hrkGGwG
# $2b$12$.vEapj9xU8z0RK0IpIGeYuRIl0ktdMt4XdJQBhVn.3K2hmvm7qD3y # $2b$12$.vEapj9xU8z0RK0IpIGeYuRIl0ktdMt4XdJQBhVn.3K2hmvm7qD3y
# $2b$12$yL3PiseU70ciwEuMVM4OtuMwR6tNuIT9vvBiBG/uyMrPxa16E2Zqu # $2b$12$yL3PiseU70ciwEuMVM4OtuMwR6tNuIT9vvBiBG/uyMrPxa16E2Zqu

View File

@ -11,7 +11,6 @@ def GetParticipant(options):
options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call. options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call.
""" """
# TODO: validate token
try: try:
pooledConnection = local_db.getPoolConnection() pooledConnection = local_db.getPoolConnection()
@ -20,7 +19,8 @@ def GetParticipant(options):
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"]}) 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"]})
else: else:
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) 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)
pooledConnection.close()
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex: except Exception as ex:
logging.error(ex) logging.error(ex)
@ -29,5 +29,7 @@ def GetParticipant(options):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps("call failed"), 500 return json.dumps("call failed"), 500
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'} finally:
if pooledConnection is not None:
pooledConnection.close()

View File

@ -13,17 +13,24 @@ def GetShipcalls(options):
No parameters, gets all entries No parameters, gets all entries
""" """
# TODO: validate token
try: try:
pooledConnection = local_db.getPoolConnection() pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection) commands = pydapper.using(pooledConnection)
query = ("SELECT id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " query = ("SELECT s.id as 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, " "flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
"anchored, moored_lock, canceled, evaluation, evaluation_message, created, modified FROM shipcall WHERE ((type = 1 OR type = 3) AND eta >= DATE(NOW() - INTERVAL %d DAY)" "tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
"OR (type = 2 AND etd >= DATE(NOW() - INTERVAL %d DAY))) " "evaluation_message, s.created as created, s.modified as modified " +
"ORDER BY eta") % (options["past_days"], options["past_days"]) "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"])
data = commands.query(query, model=model.Shipcall) data = commands.query(query, model=model.Shipcall)
for shipcall in data: for shipcall in data:
@ -33,7 +40,7 @@ def GetShipcalls(options):
pa = model.Participant_Assignment(record["participant_id"], record["type"]) pa = model.Participant_Assignment(record["participant_id"], record["type"])
shipcall.participants.append(pa) shipcall.participants.append(pa)
pooledConnection.close() return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex: except Exception as ex:
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
@ -43,7 +50,9 @@ def GetShipcalls(options):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} 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'} finally:
if pooledConnection is not None:
pooledConnection.close()
def PostShipcalls(schemaModel): def PostShipcalls(schemaModel):
@ -111,8 +120,6 @@ def PostShipcalls(schemaModel):
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id
pooledConnection.close()
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex: except Exception as ex:
@ -123,6 +130,10 @@ def PostShipcalls(schemaModel):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
if pooledConnection is not None:
pooledConnection.close()
def PutShipcalls(schemaModel): def PutShipcalls(schemaModel):
""" """
@ -194,9 +205,6 @@ def PutShipcalls(schemaModel):
commands.execute(dquery, param={"existing_id" : elem["id"]}) commands.execute(dquery, param={"existing_id" : elem["id"]})
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["id"]) # schemaModel["id"] refers to the shipcall id
pooledConnection.close()
return json.dumps({"id" : schemaModel["id"]}), 200 return json.dumps({"id" : schemaModel["id"]}), 200
@ -208,5 +216,7 @@ def PutShipcalls(schemaModel):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
if pooledConnection is not None:
pooledConnection.close()

View File

@ -17,7 +17,8 @@ def GetShips(token):
pooledConnection = local_db.getPoolConnection() pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection) commands = pydapper.using(pooledConnection)
data = commands.query("SELECT id, name, imo, callsign, participant_id, length, width, is_tug, bollard_pull, eni, created, modified, deleted FROM ship ORDER BY name", model=model.Ship) data = commands.query("SELECT id, name, imo, callsign, participant_id, length, width, is_tug, bollard_pull, eni, created, modified, deleted FROM ship ORDER BY name", model=model.Ship)
pooledConnection.close()
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex: except Exception as ex:
logging.error(ex) logging.error(ex)
@ -26,7 +27,10 @@ def GetShips(token):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} 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'} finally:
if pooledConnection is not None:
pooledConnection.close()

View File

@ -85,8 +85,6 @@ def PostTimes(schemaModel):
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall' # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall'
evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id' evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id'
pooledConnection.close()
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex: except Exception as ex:
@ -96,6 +94,10 @@ def PostTimes(schemaModel):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
if pooledConnection is not None:
pooledConnection.close()
def PutTimes(schemaModel): def PutTimes(schemaModel):
""" """
@ -130,8 +132,6 @@ def PutTimes(schemaModel):
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall' # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall'
evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id' evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id'
pooledConnection.close()
# if affected_rows == 1: # this doesn't work as expected # if affected_rows == 1: # this doesn't work as expected
return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
@ -145,6 +145,10 @@ def PutTimes(schemaModel):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
if pooledConnection is not None:
pooledConnection.close()
def DeleteTimes(options): def DeleteTimes(options):
""" """
:param options: A dictionary containing all the paramters for the Operations :param options: A dictionary containing all the paramters for the Operations
@ -156,7 +160,6 @@ def DeleteTimes(options):
pooledConnection = local_db.getPoolConnection() pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection) commands = pydapper.using(pooledConnection)
affected_rows = commands.execute("DELETE FROM times WHERE id = ?id?", param={"id" : options["id"]}) affected_rows = commands.execute("DELETE FROM times WHERE id = ?id?", param={"id" : options["id"]})
pooledConnection.close()
if affected_rows == 1: if affected_rows == 1:
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
@ -170,4 +173,8 @@ def DeleteTimes(options):
print(ex) print(ex)
result = {} result = {}
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
if pooledConnection is not None:
pooledConnection.close()

View File

@ -56,8 +56,6 @@ def PutUser(schemaModel):
result["message"] = "old password invalid" result["message"] = "old password invalid"
return json.dumps(result), 400, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 400, {'Content-Type': 'application/json; charset=utf-8'}
pooledConnection.close()
return json.dumps({"id" : schemaModel["id"]}), 200 return json.dumps({"id" : schemaModel["id"]}), 200
except Exception as ex: except Exception as ex:
@ -67,5 +65,8 @@ def PutUser(schemaModel):
result["message"] = "call failed" result["message"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'} return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
if pooledConnection is not None:
pooledConnection.close()

View File

@ -2,7 +2,7 @@ from setuptools import find_packages, setup
setup( setup(
name='BreCal', name='BreCal',
version='1.1.5', version='1.1.6',
packages=find_packages(), packages=find_packages(),
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,