mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-05-19 07:36:26 +02:00
Version 3.0.375
This commit is contained in:
parent
2c790239cb
commit
ca080c87c0
194 changed files with 10092 additions and 10464 deletions
|
@ -104,7 +104,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
|
|||
/// <summary>
|
||||
/// Converts the instance to text.
|
||||
/// </summary>
|
||||
public new string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Id={Bike.Id}{(Bike.WheelType != null ? $", wheel(s)={Bike.WheelType}" : string.Empty)}{(Bike.TypeOfBike != null ? $"type={Bike.TypeOfBike}" : "")}, state={State}, location={(!string.IsNullOrEmpty(StationId) ? $"Station {StationId}" : "On the road")}, is demo={IsDemo}.";
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
|
|||
/// <summary>
|
||||
/// Converts the instance to text.
|
||||
/// </summary>
|
||||
public new string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Id={Id}{(WheelType != null ? $", wheel(s)={WheelType}" : string.Empty)}{(TypeOfBike != null ? $", type={TypeOfBike}" : "")}, demo={IsDemo}, state={State.ToString()}, location={(!string.IsNullOrEmpty(StationId) ? $"Station {StationId}" : "On the road")}.";
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BC
|
|||
/// </summary>
|
||||
Uri OperatorUri { get; }
|
||||
|
||||
/// <summary> Holds description about the tarif. </summary>
|
||||
/// <summary> Holds description about the tariff. </summary>
|
||||
RentalDescription TariffDescription { get; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BikeNS
|
|||
}
|
||||
|
||||
/// <summary> Converts the instance to text.</summary>
|
||||
public new string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return WheelType == null || TypeOfBike == null
|
||||
? $"Id={Id}{(!string.IsNullOrEmpty(Description) ? $", {Description}" : "")}"
|
||||
|
|
|
@ -110,9 +110,9 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
|
|||
LockService,
|
||||
listener: listener);
|
||||
|
||||
public new string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Id={Id}{(TypeOfBike != null ? $";type={TypeOfBike}" : "")};state={State.ToString()}";
|
||||
return $"Id={Id}{(TypeOfBike != null ? $";type={TypeOfBike}" : "")};state={State.ToString()};Lock id={LockInfo.Id}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using TINK.Services.BluetoothLock;
|
|||
using TINK.Services.BluetoothLock.Exception;
|
||||
using TINK.Services.BluetoothLock.Tdo;
|
||||
using TINK.Services.Geolocation;
|
||||
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
||||
{
|
||||
|
@ -91,9 +92,9 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
{
|
||||
listener.ReportStep(step);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Error("An exception {exception} was thrown invoking step- action for set {step} ", ex, step);
|
||||
Log.ForContext<T>().Error("An exception {@exception} was thrown invoking step-action for step {step} ", exception, step);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,9 +108,9 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
{
|
||||
await listener.ReportStateAsync(state, message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Error("An exception {exception} was thrown invoking state- action for set {state} ", ex, state);
|
||||
Log.ForContext<T>().Error("An exception {@exception} was thrown invoking state-action for state {state} ", exception, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,21 +119,21 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
{
|
||||
// Step: Wait until getting geolocation has completed.
|
||||
InvokeCurrentStep(Step.WaitStopPollingQueryLocation);
|
||||
Log.ForContext<T>().Debug($"Waiting on steps {Step.StartingQueryingLocation} and {Step.StartStopingPolling} to finish...");
|
||||
Log.ForContext<T>().Information($"Waiting on steps {Step.StartingQueryingLocation} and {Step.StartStopingPolling} to finish...");
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(new List<Task> { locationTask, stopPollingTask ?? Task.CompletedTask });
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<T>().Information("Canceling query location/ wait for polling task to finish failed. {Exception}", ex);
|
||||
await InvokeCurrentStateAsync(State.WaitGeolocationException, ex.Message);
|
||||
Log.ForContext<T>().Information("Canceling query location/ wait for polling task to finish failed. {@exception}", exception);
|
||||
await InvokeCurrentStateAsync(State.WaitGeolocationException, exception.Message);
|
||||
InvokeCurrentStep(Step.QueryLocationTerminated);
|
||||
return null;
|
||||
}
|
||||
|
||||
Log.ForContext<T>().Debug($"Steps {Step.StartingQueryingLocation} and {Step.StartStopingPolling} finished.");
|
||||
Log.ForContext<T>().Information($"Steps {Step.StartingQueryingLocation} and {Step.StartStopingPolling} finished.");
|
||||
InvokeCurrentStep(Step.QueryLocationTerminated);
|
||||
return locationTask.Result;
|
||||
}
|
||||
|
@ -155,21 +156,23 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
Age = timeStamp.Subtract(location.Timestamp.DateTime),
|
||||
}.Build()
|
||||
: null);
|
||||
Log.ForContext<T>().Information("Backend updated for bike {bikeId} successfully.", bike.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<ReservedOpen>().Information("Updating backend for bike {bikeId} failed.", bike.Id);
|
||||
//BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
if (exception is WebConnectFailureException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<T>().Information("User locked bike {bike} in order to pause ride but updating failed (Copri server not reachable).", bike);
|
||||
Log.ForContext<T>().Debug("Copri server not reachable.");
|
||||
await InvokeCurrentStateAsync(State.WebConnectFailed, exception.Message);
|
||||
return;
|
||||
}
|
||||
else if (exception is ResponseException copriException)
|
||||
{
|
||||
// Copri server is not reachable.
|
||||
Log.ForContext<T>().Information("User locked bike {bike} in order to pause ride but updating failed. Message: {Message} Details: {Details}", bike, copriException.Message, copriException.Response);
|
||||
Log.ForContext<T>().Debug("Message: {Message} Details: {Details}", copriException.Message, copriException.Response);
|
||||
await InvokeCurrentStateAsync(State.ResponseIsInvalid, exception.Message);
|
||||
return;
|
||||
}
|
||||
|
@ -192,48 +195,49 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
try
|
||||
{
|
||||
currentLocationTask = geolocation.GetAsync(ctsLocation.Token, timeStampNow);
|
||||
Log.ForContext<T>().Information("Starting query location successful.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<T>().Information("Starting query location failed. {Exception}", bike, ex);
|
||||
await InvokeCurrentStateAsync(State.StartGeolocationException, ex.Message);
|
||||
Log.ForContext<T>().Information("Starting query location failed. {@exception}", exception);
|
||||
await InvokeCurrentStateAsync(State.StartGeolocationException, exception.Message);
|
||||
}
|
||||
|
||||
//// Step: Close lock.
|
||||
IGeolocation currentLocation;
|
||||
Log.ForContext<T>().Debug($"Starting step {Step.ClosingLock}...");
|
||||
Log.ForContext<T>().Information($"Starting step {Step.ClosingLock}...");
|
||||
InvokeCurrentStep(Step.ClosingLock);
|
||||
LockitLockingState? lockingState;
|
||||
try
|
||||
{
|
||||
lockingState = await lockService[bike.LockInfo.Id].CloseAsync();
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} closed successfully.", bike.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Information("Lock of bike {bikeId} can not be closed.", bike.Id);
|
||||
if (exception is OutOfReachException)
|
||||
{
|
||||
Log.ForContext<T>().Debug("Lock can not be closed. {Exception}", exception);
|
||||
Log.ForContext<T>().Debug("Lock is out of reach");
|
||||
await InvokeCurrentStateAsync(State.OutOfReachError, exception.Message);
|
||||
}
|
||||
else if (exception is CouldntCloseMovingException)
|
||||
{
|
||||
Log.ForContext<T>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
Log.ForContext<T>().Debug("Lock is moving.");
|
||||
await InvokeCurrentStateAsync(State.CouldntCloseMovingError, exception.Message);
|
||||
}
|
||||
else if (exception is CouldntCloseBoltBlockedException)
|
||||
{
|
||||
Log.ForContext<T>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
Log.ForContext<T>().Debug("Bold is blocked.}");
|
||||
await InvokeCurrentStateAsync(State.CouldntCloseBoltBlockedError, exception.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ForContext<T>().Debug("Lock can not be closed. Lock is out of reach. {Exception}", exception);
|
||||
Log.ForContext<T>().Debug("{@exception}", exception);
|
||||
await InvokeCurrentStateAsync(State.GeneralCloseError, exception.Message);
|
||||
}
|
||||
|
||||
Log.ForContext<T>().Error("Lock can not be closed. {Exception}", exception);
|
||||
|
||||
// Signal cts to cancel getting geolocation.
|
||||
ctsLocation.Cancel();
|
||||
|
||||
|
|
|
@ -75,9 +75,9 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
try
|
||||
{
|
||||
listener.ReportStep(step);
|
||||
} catch (Exception ex)
|
||||
} catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Error("An exception {exception} was thrown invoking step- action for set {step} ", ex, step);
|
||||
Log.ForContext<T>().Error("An exception {@exception} was thrown invoking step-action for step {step} ", exception, step);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,9 +91,9 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
{
|
||||
await listener.ReportStateAsync(state, message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Error("An exception {exception} was thrown invoking state- action for set {state} ", ex, state);
|
||||
Log.ForContext<T>().Error("An exception {@exception} was thrown invoking state-action for state {state} ", exception, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,8 +121,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
if (deviceState != DeviceState.Connected)
|
||||
{
|
||||
// Geolocation can not be queried because bike is not around.
|
||||
Log.ForContext<T>().Information("User selected booked bike {bike} but returning failed. There is no geolocation information available.", bike);
|
||||
|
||||
Log.ForContext<T>().Information("User selected booked bike {bikeId} but returning failed. There is no geolocation information available.", bike.Id);
|
||||
await InvokeCurrentStateAsync(State.DisconnetedNoLocationError, "");
|
||||
|
||||
//// Step: Disconnect lock.
|
||||
|
@ -130,11 +129,11 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
try
|
||||
{
|
||||
bike.LockInfo.State = await lockService.DisconnectAsync(bike.LockInfo.Id, bike.LockInfo.Guid);
|
||||
Log.ForContext<T>().Information("Lock from bike {bikeId} disconnected successfully.", bike.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<T>().Error("Lock can not be disconnected. {Exception}", exception);
|
||||
|
||||
Log.ForContext<T>().Information("Lock from bike {bikeId} can not be disconnected. {@exception}", bike.Id, exception);
|
||||
await InvokeCurrentStateAsync(State.DisconnectError, exception.Message);
|
||||
}
|
||||
|
||||
|
@ -148,20 +147,19 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command
|
|||
try
|
||||
{
|
||||
closingLockLocation = await geolocation.GetAsync(ctsLocation.Token, DateTime.Now);
|
||||
Log.ForContext<T>().Information("Query location of lock from bike {bikeId} successful.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
// No location information available.
|
||||
Log.ForContext<T>().Information("Returning closed bike {Bike} is not possible. Geolocation query failed. {Exception}", bike, ex);
|
||||
|
||||
await InvokeCurrentStateAsync(State.QueryLocationFailed, ex.Message);
|
||||
Log.ForContext<T>().Information("Geolocation query failed. {@exception}", exception);
|
||||
await InvokeCurrentStateAsync(State.QueryLocationFailed, exception.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
await InvokeCurrentStateAsync(State.QueryLocationSucceeded, string.Empty);
|
||||
|
||||
// Update last lock state time
|
||||
|
||||
// save geolocation data for sending to backend
|
||||
var currentLocationDto = closingLockLocation != null
|
||||
? new LocationDto.Builder
|
||||
|
|
|
@ -185,7 +185,7 @@ namespace TINK.Model.Connector
|
|||
|
||||
}
|
||||
|
||||
/// <summary> Updates COPRI lock state for a booked bike. </summary>
|
||||
/// <summary> Updates COPRI lock state for a booked or reserved bike. </summary>
|
||||
/// <param name="bike">Bike to update locking state for.</param>
|
||||
/// <param name="location">Location of the bike.</param>
|
||||
/// <returns>Response on updating locking state.</returns>
|
||||
|
@ -198,7 +198,7 @@ namespace TINK.Model.Connector
|
|||
throw new ArgumentNullException("Can not update locking state of bike. No bike object available.");
|
||||
}
|
||||
|
||||
if (bike.State.Value != State.InUseStateEnum.Booked)
|
||||
if (bike.State.Value != State.InUseStateEnum.Booked && bike.State.Value != State.InUseStateEnum.Reserved)
|
||||
{
|
||||
throw new ArgumentNullException($"Can not update locking state of bike. Unexpected booking state {bike.State} detected.");
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ namespace TINK.Model.Connector
|
|||
public class ConnectorCache : IConnector
|
||||
{
|
||||
/// <summary>Constructs a copri connector object to connect to cache.</summary>
|
||||
/// <remarks>Used for offline szenario to ensure responsiveness of app by preventing hopeless tries to communicate with COPRI. </remarks>
|
||||
/// <remarks>Used for offline scenario to ensure responsiveness of app by preventing hopeless tries to communicate with COPRI. </remarks>
|
||||
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
|
||||
/// <param name="sessionCookie"> Holds the session cookie.</param>
|
||||
/// <param name="mail">Mail of user.</param>
|
||||
/// <param name="smartDevice">Holds info about smart device.</param>
|
||||
/// <param name="server"> Is null in production and migh be a mock in testing context.</param>
|
||||
/// <param name="server"> Is null in production and might be a mock in testing context.</param>
|
||||
public ConnectorCache(
|
||||
AppContextInfo appContextInfo,
|
||||
string uiIsoLangugageName,
|
||||
|
@ -36,10 +36,10 @@ namespace TINK.Model.Connector
|
|||
mail);
|
||||
}
|
||||
|
||||
/// <summary> Object for queriying stations and bikes.</summary>
|
||||
/// <summary> Object for querying stations and bikes.</summary>
|
||||
public ICommand Command { get; private set; }
|
||||
|
||||
/// <summary> Object for queriying stations and bikes.</summary>
|
||||
/// <summary> Object for querying stations and bikes.</summary>
|
||||
public IQuery Query { get; private set; }
|
||||
|
||||
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
|
||||
|
|
|
@ -64,9 +64,10 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
/// <param name="operatorUri">Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.</param>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync(Uri operatorUri = null)
|
||||
{
|
||||
var result = await m_oInnerQuery.GetBikesAsync();
|
||||
var result = await m_oInnerQuery.GetBikesAsync(operatorUri);
|
||||
return new Result<BikeCollection>(
|
||||
result.Source,
|
||||
new BikeCollection(DoFilter(result.Response, Filter)),
|
||||
|
@ -129,6 +130,7 @@ namespace TINK.Model.Connector
|
|||
station.Group,
|
||||
station.Position,
|
||||
station.StationName,
|
||||
station.OperatorUri,
|
||||
station.OperatorData,
|
||||
new BikeGroupCol(station.BikeGroups
|
||||
.Where(group => filter.DoFilter(new List<string> { group.Group }).Count() > 0))) as IStation)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
namespace TINK.Model.Connector
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
public interface IConnector
|
||||
{
|
||||
/// <summary> Object for queriying stations and bikes.</summary>
|
||||
/// <summary> Object for querying stations and bikes.</summary>
|
||||
ICommand Command { get; }
|
||||
|
||||
/// <summary> Object for queriying stations and bikes.</summary>
|
||||
/// <summary> Object for querying stations and bikes.</summary>
|
||||
IQuery Query { get; }
|
||||
|
||||
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
|
||||
|
|
|
@ -56,9 +56,10 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
/// <param name="operatorUri">Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.</param>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync(Uri operatorUri = null)
|
||||
{
|
||||
var result = await m_oInnerQuery.GetBikesAsync();
|
||||
var result = await m_oInnerQuery.GetBikesAsync(operatorUri);
|
||||
return new Result<BikeCollection>(
|
||||
result.Source,
|
||||
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
|
||||
|
|
|
@ -71,14 +71,15 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Gets bikes available. </summary>
|
||||
/// <param name="operatorUri">Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.</param>
|
||||
/// <returns>Collection of bikes.</returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync(Uri operatorUri = null)
|
||||
{
|
||||
var result = await server.GetBikesAvailable();
|
||||
var result = await server.GetBikesAvailable(operatorUri: operatorUri);
|
||||
|
||||
if (result.Source != typeof(CopriCallsMonkeyStore))
|
||||
{
|
||||
server.AddToCache(result);
|
||||
server.AddToCache(result, operatorUri);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -127,21 +127,24 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Gets bikes available and bikes occupied. </summary>
|
||||
/// <param name="operatorUri">Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.</param>
|
||||
/// <returns>Collection of bikes.</returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync(Uri operatorUri = null)
|
||||
{
|
||||
var bikesAvailableResponse = await Server.GetBikesAvailable();
|
||||
var bikesAvailableResponse = await Server.GetBikesAvailable(operatorUri: operatorUri);
|
||||
|
||||
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesAvailableResponse.Exception != null)
|
||||
{
|
||||
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available read from cache. Reading bikes occupied from cache as well.");
|
||||
// Bikes were read from cache.
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available and bikes occupied from cache invoking one single call.");
|
||||
return new Result<BikeCollection>(
|
||||
bikesAvailableResponse.Source,
|
||||
BikeCollectionFactory.GetBikesAll(
|
||||
bikesAvailableResponse.Response?.bikes?.Values,
|
||||
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
|
||||
operatorUri?.AbsoluteUri == null ?
|
||||
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values // Get bikes occupied from cache as well to avoid inconsistencies.
|
||||
: bikesAvailableResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider,
|
||||
Bikes.BikeInfoNS.BC.DataSource.Cache),
|
||||
|
@ -149,7 +152,27 @@ namespace TINK.Model.Connector
|
|||
bikesAvailableResponse.Exception);
|
||||
}
|
||||
|
||||
var bikesOccupiedResponse = await Server.GetBikesOccupied();
|
||||
if (operatorUri?.AbsoluteUri != null)
|
||||
{
|
||||
// Both types bikes could read from copri successfully => update cache
|
||||
Server.AddToCache(bikesAvailableResponse, operatorUri);
|
||||
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available and occupied read successfully from server invoking one single request.");
|
||||
return new Result<BikeCollection>(
|
||||
bikesAvailableResponse.Source,
|
||||
BikeCollectionFactory.GetBikesAll(
|
||||
bikesAvailableResponse.Response?.bikes?.Values,
|
||||
bikesAvailableResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider,
|
||||
Bikes.BikeInfoNS.BC.DataSource.Copri),
|
||||
bikesAvailableResponse.GeneralData,
|
||||
bikesAvailableResponse.Exception != null ? new AggregateException(new[] { bikesAvailableResponse.Exception }) : null);
|
||||
}
|
||||
|
||||
/// Legacy implementation: GetBikesOccupied are not returned in <see cref="ICachedCopriServer.GetBikesAvailable"/> call.
|
||||
/// A separate call <see cref="ICachedCopriServer.GetBikesOccupied"/> is required to retrieve all bikes.
|
||||
var bikesOccupiedResponse = await Server.GetBikesOccupied(); /* Only query bikes occupied if operator uri is unknown. */
|
||||
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesOccupiedResponse.Exception != null)
|
||||
{
|
||||
|
@ -158,7 +181,7 @@ namespace TINK.Model.Connector
|
|||
return new Result<BikeCollection>(
|
||||
bikesOccupiedResponse.Source,
|
||||
BikeCollectionFactory.GetBikesAll(
|
||||
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
|
||||
(await Server.GetBikesAvailable(true, operatorUri)).Response?.bikes?.Values,
|
||||
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
|
||||
Mail,
|
||||
DateTimeProvider,
|
||||
|
@ -168,7 +191,7 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
// Both types bikes could read from copri => update cache
|
||||
Server.AddToCache(bikesAvailableResponse);
|
||||
Server.AddToCache(bikesAvailableResponse, operatorUri);
|
||||
Server.AddToCache(bikesOccupiedResponse);
|
||||
|
||||
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available and occupied read successfully from server.");
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bikes;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
|
@ -14,7 +15,8 @@ namespace TINK.Model.Connector
|
|||
Task<Result<BikeCollection>> GetBikesOccupiedAsync();
|
||||
|
||||
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
|
||||
/// <param name="operatorUri">Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.</param>
|
||||
/// <returns>Collection of bikes.</returns>
|
||||
Task<Result<BikeCollection>> GetBikesAsync();
|
||||
Task<Result<BikeCollection>> GetBikesAsync(Uri operatorUri = null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,10 +54,11 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Gets bikes occupied. </summary>
|
||||
/// <param name="operatorUri">Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.</param>
|
||||
/// <returns> Collection of bikes. </returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync(Uri operatorUri = null)
|
||||
{
|
||||
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
|
||||
var bikesAvailableResponse = await server.GetBikesAvailableAsync(operatorUri);
|
||||
return new Result<BikeCollection>(
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
bikesAvailableResponse.GetBikesAvailable(Bikes.BikeInfoNS.BC.DataSource.Cache),
|
||||
|
|
|
@ -69,10 +69,11 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Gets bikes available and bikes occupied. </summary>
|
||||
/// <param name="operatorUri">Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.</param>
|
||||
/// <returns>Collection of bikes.</returns>
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync()
|
||||
public async Task<Result<BikeCollection>> GetBikesAsync(Uri operatorUri = null)
|
||||
{
|
||||
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
|
||||
var bikesAvailableResponse = await server.GetBikesAvailableAsync(operatorUri);
|
||||
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
|
||||
|
||||
return new Result<BikeCollection>(
|
||||
|
|
|
@ -361,9 +361,35 @@ namespace TINK.Model.Connector
|
|||
/// <returns>Operator Uri</returns>
|
||||
public static Uri GetOperatorUri(this BikeInfoBase bikeInfo)
|
||||
{
|
||||
return bikeInfo?.uri_operator != null && !string.IsNullOrEmpty(bikeInfo?.uri_operator)
|
||||
? new Uri($"{bikeInfo.uri_operator}/{CopriServerUriList.REST_RESOURCE_ROOT}")
|
||||
: null;
|
||||
if (Uri.TryCreate(bikeInfo?.uri_operator, UriKind.Absolute, out var operatorUri))
|
||||
{
|
||||
// Valid uri detected.
|
||||
return new Uri($"{operatorUri.AbsoluteUri}/{CopriServerUriList.REST_RESOURCE_ROOT}");
|
||||
}
|
||||
|
||||
Log.Error(!string.IsNullOrEmpty(bikeInfo?.uri_operator)
|
||||
? $"Operator uri can not be extracted from bike info base object {bikeInfo.uri_operator}. Uri is not valid."
|
||||
: "Operator uri can not be extracted from bike info base object. Entry is null or empty.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the operator Uri from response.
|
||||
/// </summary>
|
||||
/// <param name="stationInfo"> Response to get uri from.</param>
|
||||
/// <returns>Operator Uri</returns>
|
||||
public static Uri GetOperatorUri(this StationInfo stationInfo)
|
||||
{
|
||||
if (Uri.TryCreate(stationInfo?.uri_operator, UriKind.Absolute, out var operatorUri))
|
||||
{
|
||||
// Valid uri detected.
|
||||
return new Uri($"{operatorUri.AbsoluteUri}/{CopriServerUriList.REST_RESOURCE_ROOT}");
|
||||
}
|
||||
|
||||
Log.Error(!string.IsNullOrEmpty(stationInfo?.uri_operator)
|
||||
? $"Operator uri can not be extracted from station object {stationInfo.uri_operator}. Uri is not valid."
|
||||
: "Operator uri can not be extracted from station object. Entry is null or empty.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary> Tries to get the copri version from response.</summary>
|
||||
|
@ -415,6 +441,7 @@ namespace TINK.Model.Connector
|
|||
station.GetGroup(),
|
||||
station.GetPosition(),
|
||||
station.description,
|
||||
station.GetOperatorUri(),
|
||||
new Data(station.operator_data?.operator_name,
|
||||
station.operator_data?.operator_phone,
|
||||
station.operator_data?.operator_hours,
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace TINK.Model.Connector.Updater
|
|||
DataSource dataSource)
|
||||
=> GetBikesAll(
|
||||
bikesAvailableResponse?.bikes?.Values,
|
||||
new BikesReservedOccupiedResponse()?.bikes_occupied?.Values, // There are no occupied bikes.
|
||||
bikesAvailableResponse?.bikes_occupied?.Values,
|
||||
string.Empty,
|
||||
() => DateTime.Now,
|
||||
dataSource);
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace TINK.Model.State
|
|||
/// Transforms object to string.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public new string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return _InUseState.Value.ToString("g");
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ namespace TINK.Model.State
|
|||
/// Transforms object to string.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public new string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return _StateInfo.ToString();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.Stations.StationNS.Operator;
|
||||
|
||||
|
@ -17,6 +18,9 @@ namespace TINK.Model.Stations.StationNS
|
|||
/// <summary> Gets the name of the station.</summary>
|
||||
string StationName { get; }
|
||||
|
||||
/// <summary> Uri of the operator or null. </summary>
|
||||
Uri OperatorUri { get; }
|
||||
|
||||
/// <summary> Holds the gps- position of the station.</summary>
|
||||
IPosition Position { get; }
|
||||
|
||||
|
@ -29,5 +33,6 @@ namespace TINK.Model.Stations.StationNS
|
|||
/// <summary> Gets bike <see cref="BikeGroupCol.Entry"/> objects. </summary>
|
||||
/// <remarks> Each entry has a name, holds the count of available bikes at station and the group value. /// </remarks>
|
||||
IBikeGroupCol BikeGroups { get; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.Stations.StationNS.Operator;
|
||||
|
||||
|
@ -15,6 +16,9 @@ namespace TINK.Model.Stations.StationNS
|
|||
/// <summary> Gets the name of the station.</summary>
|
||||
public string StationName => string.Empty;
|
||||
|
||||
/// <summary> Uri of the operator or null. </summary>
|
||||
public Uri OperatorUri => null;
|
||||
|
||||
/// <summary> Holds the gps- position of the station.</summary>
|
||||
public IPosition Position => PositionFactory.Create();
|
||||
|
||||
|
|
|
@ -12,11 +12,13 @@ namespace TINK.Model.Stations.StationNS
|
|||
/// <param name="group">Group (TINK, Konrad) to which station is related.</param>
|
||||
/// <param name="position">GPS- position of the station.</param>
|
||||
/// <param name="stationName">Name of the station.</param>
|
||||
/// <param name="operatorUri">Uri of the operator or null.</param>
|
||||
public Station(
|
||||
string id,
|
||||
IEnumerable<string> group = null,
|
||||
IPosition position = null,
|
||||
string stationName = "",
|
||||
Uri operatorUri = null,
|
||||
IData operatorData = null,
|
||||
IBikeGroupCol bikeGropCol = null)
|
||||
{
|
||||
|
@ -26,6 +28,7 @@ namespace TINK.Model.Stations.StationNS
|
|||
StationName = stationName ?? string.Empty;
|
||||
OperatorData = operatorData ?? new Data();
|
||||
BikeGroups = bikeGropCol ?? new BikeGroupCol();
|
||||
OperatorUri = operatorUri;
|
||||
}
|
||||
|
||||
/// <summary> Holds the unique id of the station.c</summary>
|
||||
|
@ -49,5 +52,8 @@ namespace TINK.Model.Stations.StationNS
|
|||
/// <summary> Gets bike <see cref="BikeGroupCol.Entry"/> objects. </summary>
|
||||
/// <remarks> Each entry has a name, holds the count of available bikes at station and the group value. /// </remarks>
|
||||
public IBikeGroupCol BikeGroups { get; }
|
||||
|
||||
/// <summary> Uri of the operator or null. </summary>
|
||||
public Uri OperatorUri { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,7 +182,6 @@ namespace TINK.Model
|
|||
ISpecialFolder specialFolder,
|
||||
ICipher cipher,
|
||||
ITheme theme,
|
||||
object arendiCentral = null,
|
||||
Action<SendOrPostCallback, object> postAction = null,
|
||||
Version currentVersion = null,
|
||||
Version lastVersion = null,
|
||||
|
@ -225,11 +224,7 @@ namespace TINK.Model
|
|||
#if BLUETOOTHLE // Requires LockItBluetoothle library.
|
||||
new Bluetoothle.LockItByGuidService(Cipher),
|
||||
#endif
|
||||
#if ARENDI // Requires LockItArendi library.
|
||||
new Arendi.LockItByGuidService(Cipher, arendiCentral),
|
||||
new Arendi.LockItByScanService(Cipher, arendiCentral),
|
||||
#endif
|
||||
new LocksServiceInReach(),
|
||||
new LocksServiceInReach(),
|
||||
new LocksServiceOutOfReach(),
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace TINK.Model.User.Account
|
|||
SwitchNoSiteCaching = 1024, // Allows to turn off/ on caching of sites displayed in app hosted by COPRI
|
||||
ReportLevel = 2048, // Allows extent to show error messages.
|
||||
SwitchTheme = 4096, // Allows user to switch theme (sharee.bike, Mein konrad, LastenRad Bayern)
|
||||
ManageAlarmAndSounds = 8192, // Allows user to manage sounds and alarm settings (lock open and connected)
|
||||
All = PickCopriServer +
|
||||
ManageCopriCacheExpiration +
|
||||
ManagePolling +
|
||||
|
@ -28,7 +29,8 @@ namespace TINK.Model.User.Account
|
|||
ShowDiagnostics +
|
||||
SwitchNoSiteCaching +
|
||||
ReportLevel +
|
||||
SwitchTheme,
|
||||
SwitchTheme +
|
||||
ManageAlarmAndSounds,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -732,6 +732,11 @@ namespace TINK.Model
|
|||
AppResources.ChangeLog_3_0_374_MK_SB,
|
||||
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 375),
|
||||
string.Format("{0} <br /> {1} <br /> {2}", AppResources.ChangeLog_MinorImprovements, AppResources.ChangeLog_PackageUpdates, AppResources.ChangeLog_MinorBugFixes),
|
||||
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary> Manges the whats new information.</summary>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue