mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-06-21 21:46:27 +02:00
Code updated to 3.0.238
This commit is contained in:
parent
3302d80678
commit
9c6a1fa92b
257 changed files with 7763 additions and 2861 deletions
|
@ -21,13 +21,13 @@ namespace TINK.Model.Bike.BC
|
|||
/// <summary> Constructs a bike object.</summary>
|
||||
protected BikeInfo(
|
||||
IStateInfo stateInfo,
|
||||
int id,
|
||||
string id,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null,
|
||||
int? currentStationId = null,
|
||||
string currentStationId = null,
|
||||
Uri operatorUri = null,
|
||||
TariffDescription tariffDescription = null)
|
||||
{
|
||||
|
@ -63,8 +63,8 @@ namespace TINK.Model.Bike.BC
|
|||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
public BikeInfo(
|
||||
int id,
|
||||
int? currentStationId,
|
||||
string id,
|
||||
string currentStationId,
|
||||
Uri operatorUri = null,
|
||||
TariffDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
|
@ -99,13 +99,13 @@ namespace TINK.Model.Bike.BC
|
|||
/// <param name="code">Booking code.</param>
|
||||
/// <param name="p_oDateTimeNowProvider">Date time provider to calculate reaining time.</param>
|
||||
public BikeInfo(
|
||||
int id,
|
||||
string id,
|
||||
bool? isDemo,
|
||||
IEnumerable<string> group,
|
||||
WheelType? wheelType,
|
||||
TypeOfBike? typeOfBike,
|
||||
string description,
|
||||
int? stationId,
|
||||
string stationId,
|
||||
Uri operatorUri,
|
||||
TariffDescription tariffDescription,
|
||||
DateTime requestedAt,
|
||||
|
@ -142,13 +142,13 @@ namespace TINK.Model.Bike.BC
|
|||
/// <param name="mailAddress">Mail address of user which booked bike.</param>
|
||||
/// <param name="code">Booking code.</param>
|
||||
public BikeInfo(
|
||||
int id,
|
||||
string id,
|
||||
bool? isDemo,
|
||||
IEnumerable<string> group,
|
||||
WheelType? wheelType,
|
||||
TypeOfBike? typeOfBike,
|
||||
string description,
|
||||
int? currentStationId,
|
||||
string currentStationId,
|
||||
Uri operatorUri,
|
||||
TariffDescription tariffDescription,
|
||||
DateTime bookedAt,
|
||||
|
@ -179,7 +179,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// <summary>
|
||||
/// Station a which bike is located, null otherwise.
|
||||
/// </summary>
|
||||
public int? CurrentStation { get; }
|
||||
public string CurrentStation { get; }
|
||||
|
||||
/// <summary> Holds description about the tarif. </summary>
|
||||
public TariffDescription TariffDescription { get; }
|
||||
|
@ -192,7 +192,7 @@ namespace TINK.Model.Bike.BC
|
|||
get { return m_oStateInfo; }
|
||||
}
|
||||
|
||||
public int Id => Bike.Id;
|
||||
public string Id => Bike.Id;
|
||||
|
||||
public WheelType? WheelType => Bike.WheelType;
|
||||
|
||||
|
@ -210,7 +210,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// </summary>
|
||||
public new string ToString()
|
||||
{
|
||||
return $"Id={Bike.Id}{(Bike.WheelType != null ? $", wheel(s)={Bike.WheelType}" : string.Empty)}{(Bike.TypeOfBike != null ? $"type={Bike.TypeOfBike}" : "")}, state={State}, location={(CurrentStation.HasValue ? $"Station {CurrentStation}" : "On the road")}, is demo={IsDemo}.";
|
||||
return $"Id={Bike.Id}{(Bike.WheelType != null ? $", wheel(s)={Bike.WheelType}" : string.Empty)}{(Bike.TypeOfBike != null ? $"type={Bike.TypeOfBike}" : "")}, state={State}, location={(!string.IsNullOrEmpty(CurrentStation)? $"Station {CurrentStation}" : "On the road")}, is demo={IsDemo}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,13 +29,13 @@ namespace TINK.Model.Bike.BC
|
|||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="stateInfo">Bike state info.</param>
|
||||
protected BikeInfoMutable(
|
||||
int id,
|
||||
string id,
|
||||
bool isDemo = BikeInfo.DEFAULTVALUEISDEMO,
|
||||
IEnumerable<string> group = null,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null,
|
||||
int? currentStationId = null,
|
||||
string currentStationId = null,
|
||||
Uri operatorUri = null,
|
||||
TariffDescription tariffDescription = null,
|
||||
Func<DateTime> dateTimeProvider = null,
|
||||
|
@ -71,7 +71,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// Station a which bike is located, null otherwise.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int? CurrentStation { get; }
|
||||
public string CurrentStation { get; }
|
||||
|
||||
/// <summary> Holds description about the tarif. </summary>
|
||||
[DataMember]
|
||||
|
@ -94,7 +94,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// <summary> Unused member. </summary>
|
||||
IStateInfoMutable IBikeInfoMutable.State => m_oStateInfo;
|
||||
|
||||
public int Id => m_oBike.Id;
|
||||
public string Id => m_oBike.Id;
|
||||
|
||||
public bool IsDemo { get; }
|
||||
|
||||
|
@ -118,7 +118,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// <returns></returns>
|
||||
public new string ToString()
|
||||
{
|
||||
return $"Id={Id}{(WheelType != null ? $", wheel(s)={WheelType}" : string.Empty)}{(TypeOfBike != null ? $", type={TypeOfBike}" : "")}, demo={IsDemo}, state={State.ToString()}, location={(CurrentStation.HasValue ? $"Station {CurrentStation}" : "On the road")}.";
|
||||
return $"Id={Id}{(WheelType != null ? $", wheel(s)={WheelType}" : string.Empty)}{(TypeOfBike != null ? $", type={TypeOfBike}" : "")}, demo={IsDemo}, state={State.ToString()}, location={(!string.IsNullOrEmpty(CurrentStation) ? $"Station {CurrentStation}" : "On the road")}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// <summary>
|
||||
/// Holds the unique id of the bike;
|
||||
/// </summary>
|
||||
int Id { get; }
|
||||
string Id { get; }
|
||||
|
||||
/// <summary> True if bike is a demo bike. </summary>
|
||||
bool IsDemo { get; }
|
||||
|
@ -37,7 +37,7 @@ namespace TINK.Model.Bike.BC
|
|||
/// <summary>
|
||||
/// Station a which bike is located, null otherwise.
|
||||
/// </summary>
|
||||
int? CurrentStation { get; }
|
||||
string CurrentStation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Uri of the operator or null, in case of single operator setup.
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace TINK.Model.Bikes.Bike.BC
|
|||
/// <summary>
|
||||
/// Holds the unique id of the bike;
|
||||
/// </summary>
|
||||
int Id { get; }
|
||||
string Id { get; }
|
||||
|
||||
/// <summary> True if bike is a demo bike. </summary>
|
||||
bool IsDemo { get; }
|
||||
|
@ -35,7 +35,7 @@ namespace TINK.Model.Bikes.Bike.BC
|
|||
/// <summary>
|
||||
/// Station a which bike is located, null otherwise.
|
||||
/// </summary>
|
||||
int? CurrentStation { get; }
|
||||
string CurrentStation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the rent state of the bike.
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace TINK.Model.Bike
|
|||
/// <param name="p_iId">Unique id of bike.</param>
|
||||
/// <param name="p_strCurrentStationName">Name of station where bike is located, null if bike is on the road.</param>
|
||||
public Bike(
|
||||
int p_iId,
|
||||
string p_iId,
|
||||
WheelType? wheelType = null,
|
||||
TypeOfBike? typeOfBike = null,
|
||||
string description = null)
|
||||
|
@ -43,7 +43,7 @@ namespace TINK.Model.Bike
|
|||
/// <summary>
|
||||
/// Holds the unique id of the bike;
|
||||
/// </summary>
|
||||
public int Id { get; }
|
||||
public string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the count of wheels.
|
||||
|
|
|
@ -18,10 +18,10 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType">Trike, two wheels, mono, ....</param>
|
||||
public BikeInfo(
|
||||
int bikeId,
|
||||
string bikeId,
|
||||
int lockId,
|
||||
Guid lockGuid,
|
||||
int? currentStationId,
|
||||
string currentStationId,
|
||||
Uri operatorUri = null,
|
||||
TariffDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
|
@ -58,7 +58,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
/// <param name="p_oDateTimeNowProvider">Date time provider to calculate reaining time.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
public BikeInfo(
|
||||
int id,
|
||||
string id,
|
||||
int lockId,
|
||||
Guid lockGuid,
|
||||
byte[] userKey,
|
||||
|
@ -66,7 +66,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
byte[] seed,
|
||||
DateTime requestedAt,
|
||||
string mailAddress,
|
||||
int? currentStationId,
|
||||
string currentStationId,
|
||||
Uri operatorUri,
|
||||
TariffDescription tariffDescription,
|
||||
Func<DateTime> dateTimeProvider,
|
||||
|
@ -106,7 +106,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
/// <param name="tariffDescription">Hold tariff description of bike.</param>
|
||||
/// <param name="wheelType"></param>
|
||||
public BikeInfo(
|
||||
int id,
|
||||
string id,
|
||||
int lockId,
|
||||
Guid lockGuid,
|
||||
byte[] userKey,
|
||||
|
@ -114,7 +114,7 @@ namespace TINK.Model.Bike.BluetoothLock
|
|||
byte[] seed,
|
||||
DateTime bookedAt,
|
||||
string mailAddress,
|
||||
int? currentStationId,
|
||||
string currentStationId,
|
||||
Uri operatorUri,
|
||||
TariffDescription tariffDescription = null,
|
||||
bool? isDemo = DEFAULTVALUEISDEMO,
|
||||
|
|
|
@ -5,8 +5,9 @@ namespace TINK.Model.Bikes.Bike
|
|||
/// <summary>
|
||||
/// Holds tariff info for a single bike.
|
||||
/// </summary>
|
||||
#if USCSHARP9
|
||||
public record TariffDescription
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the tariff.
|
||||
/// </summary>
|
||||
|
@ -37,4 +38,38 @@ namespace TINK.Model.Bikes.Bike
|
|||
/// </summary>
|
||||
public double MaxFeeEuroPerDay { get; init; }
|
||||
}
|
||||
#else
|
||||
public class TariffDescription
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the tariff.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of the tariff.
|
||||
/// </summary>
|
||||
public int? Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Costs per hour in euro.
|
||||
/// </summary>
|
||||
public double FeeEuroPerHour { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Costs of the abo per month.
|
||||
/// </summary>
|
||||
public double AboEuroPerMonth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Costs per hour in euro.
|
||||
/// </summary>
|
||||
public TimeSpan FreeTimePerSession { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Max. costs per day in euro.
|
||||
/// </summary>
|
||||
public double MaxFeeEuroPerDay { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -11,37 +11,37 @@ namespace TINK.Model.Bike
|
|||
public class BikeCollection : IBikeDictionary<BikeInfo>
|
||||
{
|
||||
/// <summary> Holds the bike dictionary object.</summary>
|
||||
private Dictionary<int, BikeInfo> BikeDictionary { get; }
|
||||
private Dictionary<string, BikeInfo> BikeDictionary { get; }
|
||||
|
||||
/// <summary>Constructs an empty bike info dictionary object.</summary>
|
||||
public BikeCollection()
|
||||
{
|
||||
BikeDictionary = new Dictionary<int, BikeInfo>();
|
||||
BikeDictionary = new Dictionary<string, BikeInfo>();
|
||||
}
|
||||
|
||||
/// <summary> Constructs a bike collection object.</summary>
|
||||
/// <param name="bikeDictionary"></param>
|
||||
public BikeCollection(Dictionary<int, BikeInfo> bikeDictionary)
|
||||
public BikeCollection(Dictionary<string, BikeInfo> bikeDictionary)
|
||||
{
|
||||
BikeDictionary = bikeDictionary ??
|
||||
throw new ArgumentNullException(nameof(bikeDictionary), "Can not construct BikeCollection object.");
|
||||
}
|
||||
|
||||
/// <summary> Gets a bike by its id.</summary>
|
||||
/// <param name="p_iId">Id of the bike to get.</param>
|
||||
/// <param name="id">Id of the bike to get.</param>
|
||||
/// <returns></returns>
|
||||
public BikeInfo GetById(int p_iId)
|
||||
public BikeInfo GetById(string id)
|
||||
{
|
||||
return BikeDictionary.FirstOrDefault(x => x.Key == p_iId).Value;
|
||||
return BikeDictionary.FirstOrDefault(x => x.Key == id).Value;
|
||||
}
|
||||
|
||||
/// <summary> Gets the count of bikes. </summary>
|
||||
public int Count => BikeDictionary.Count;
|
||||
|
||||
/// <summary> Gets if a bike with given id exists.</summary>
|
||||
/// <param name="p_iId">Id of bike.</param>
|
||||
/// <param name="id">Id of bike.</param>
|
||||
/// <returns>True if bike is contained, false otherwise.</returns>
|
||||
public bool ContainsKey(int p_iId) => BikeDictionary.Keys.Contains(p_iId);
|
||||
public bool ContainsKey(string id) => BikeDictionary.Keys.Contains(id);
|
||||
|
||||
/// <summary> Gets the enumerator. </summary>
|
||||
/// <returns>Enumerator object.</returns>
|
||||
|
|
|
@ -14,11 +14,11 @@ namespace TINK.Model
|
|||
/// <returns>BikeCollection holding bikes at given station or empty BikeCollection, if there are no bikes.</returns>
|
||||
public static BikeCollection GetAtStation(
|
||||
this BikeCollection bikesAtAnyStation,
|
||||
int? selectedStation)
|
||||
string selectedStation)
|
||||
{
|
||||
return new BikeCollection(bikesAtAnyStation?
|
||||
.Where(bike => selectedStation.HasValue && bike.CurrentStation == selectedStation.Value)
|
||||
.ToDictionary(x => x.Id) ?? new Dictionary<int, BikeInfo>());
|
||||
.Where(bike => !string.IsNullOrEmpty(selectedStation) && bike.CurrentStation == selectedStation)
|
||||
.ToDictionary(x => x.Id) ?? new Dictionary<string, BikeInfo>());
|
||||
}
|
||||
|
||||
/// <summary> Filters bikes by bike type. </summary>
|
||||
|
@ -28,7 +28,7 @@ namespace TINK.Model
|
|||
{
|
||||
return new BikeCollection(bcAndLockItBikes?
|
||||
.Where(bike => bike is Bike.BluetoothLock.BikeInfo)
|
||||
.ToDictionary(x => x.Id) ?? new Dictionary<int, BikeInfo>());
|
||||
.ToDictionary(x => x.Id) ?? new Dictionary<string, BikeInfo>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace TINK.Model.Bike
|
|||
// Update bike.
|
||||
GetById(bikeInfo.Id).State.Load(bikeInfo.State);
|
||||
|
||||
if (bikesToBeRemoved.Contains<int>(bikeInfo.Id))
|
||||
if (bikesToBeRemoved.Contains<string>(bikeInfo.Id))
|
||||
{
|
||||
// Remove list from obsolete list.
|
||||
bikesToBeRemoved.Remove(bikeInfo.Id);
|
||||
|
@ -86,20 +86,20 @@ namespace TINK.Model.Bike
|
|||
private set;
|
||||
}
|
||||
|
||||
public void SetSelectedBike(int p_intId)
|
||||
public void SetSelectedBike(string id)
|
||||
{
|
||||
SelectedBike = GetById(p_intId);
|
||||
SelectedBike = GetById(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a bike by its id.
|
||||
/// </summary>
|
||||
/// <param name="p_iId"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public BikeInfoMutable GetById(int p_iId)
|
||||
public BikeInfoMutable GetById(string id)
|
||||
{
|
||||
{
|
||||
return this.FirstOrDefault(bike => bike.Id == p_iId);
|
||||
return this.FirstOrDefault(bike => bike.Id == id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,18 +108,18 @@ namespace TINK.Model.Bike
|
|||
/// </summary>
|
||||
/// <param name="p_strKey">Key to check.</param>
|
||||
/// <returns>True if bike exists.</returns>
|
||||
public bool ContainsKey(int p_iId)
|
||||
public bool ContainsKey(string id)
|
||||
{
|
||||
return GetById(p_iId) != null;
|
||||
return GetById(id) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a bike by its id.
|
||||
/// </summary>
|
||||
/// <param name="p_iId">Id of bike to be removed.</param>
|
||||
public void RemoveById(int p_iId)
|
||||
/// <param name="id">Id of bike to be removed.</param>
|
||||
public void RemoveById(string id)
|
||||
{
|
||||
var l_oBike = GetById(p_iId);
|
||||
var l_oBike = GetById(id);
|
||||
if (l_oBike == null)
|
||||
{
|
||||
// Nothing to do if bike does not exists.
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace TINK.Model.Bike
|
|||
IEnumerable<BluetoothLock.LockInfo> locksInfo)
|
||||
{
|
||||
|
||||
var updatedBikesCollection = new Dictionary<int, BC.BikeInfo>();
|
||||
var updatedBikesCollection = new Dictionary<string, BC.BikeInfo>();
|
||||
|
||||
foreach (var bikeInfo in bikes)
|
||||
{
|
||||
|
|
|
@ -7,29 +7,29 @@ namespace TINK.Model.Bike
|
|||
/// <summary>
|
||||
/// Gets a bike by its id.
|
||||
/// </summary>
|
||||
/// <param name="p_iId"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
T GetById(int p_iId);
|
||||
T GetById(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Deteermines whether a bike by given key exists.
|
||||
/// </summary>
|
||||
/// <param name="p_strKey">Key to check.</param>
|
||||
/// <returns>True if bike exists.</returns>
|
||||
bool ContainsKey(int p_iId);
|
||||
bool ContainsKey(string id);
|
||||
}
|
||||
public interface IBikeDictionaryMutable<T> : IBikeDictionary<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Removes a bike by its id.
|
||||
/// </summary>
|
||||
/// <param name="p_iId">Id of bike to be removed.</param>
|
||||
void RemoveById(int p_iId);
|
||||
/// <param name="id">Id of bike to be removed.</param>
|
||||
void RemoveById(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new element to dictinary.
|
||||
/// </summary>
|
||||
/// <param name="p_oNewElement">New element to add.</param>
|
||||
void Add(T p_oNewElement);
|
||||
/// <param name="newElement">New element to add.</param>
|
||||
void Add(T newElement);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Model.Repository.Request;
|
||||
using TINK.Model.Repository.Response;
|
||||
using TINK.Repository;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Device;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -122,7 +123,8 @@ namespace TINK.Model.Connector
|
|||
|
||||
public async Task DoReturn(
|
||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
|
||||
LocationDto location)
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice)
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected returning request detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
|
@ -132,7 +134,11 @@ namespace TINK.Model.Connector
|
|||
/// Submits feedback to copri server.
|
||||
/// </summary>
|
||||
/// <param name="userFeedback">Feedback to submit.</param>
|
||||
#if USCSHARP9
|
||||
public async Task DoSubmitFeedback(ICommand.IUserFeedback userFeedback, Uri opertorUri)
|
||||
#else
|
||||
public async Task DoSubmitFeedback(IUserFeedback userFeedback, Uri opertorUri)
|
||||
#endif
|
||||
{
|
||||
Log.ForContext<Command>().Error("Unexpected submit feedback request detected. No user logged in.");
|
||||
await Task.CompletedTask;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike.BluetoothLock;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Model.Repository.Exception;
|
||||
using TINK.Model.Repository.Request;
|
||||
using TINK.Model.Repository.Response;
|
||||
using TINK.Repository;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Device;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ namespace TINK.Model.Connector
|
|||
/// Logs user in.
|
||||
/// If log in succeeds either and session might be updated if it was no more valid (logged in by an different device).
|
||||
/// If log in fails (password modified) session cookie is set to empty.
|
||||
/// If communication fails an TINK.Model.Repository.Exception is thrown.
|
||||
/// If communication fails an TINK.Repository.Exception is thrown.
|
||||
/// </summary>
|
||||
/// <param name="p_oAccount">Account to use for login.</param>
|
||||
public Task<IAccount> DoLogin(string p_strMail, string p_strPassword, string p_strDeviceId)
|
||||
|
@ -242,12 +243,13 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Request to return a bike.</summary>
|
||||
/// <param name="latitude">Latitude of the bike.</param>
|
||||
/// <param name="longitude">Longitude of the bike.</param>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
/// <param name="locaton">Position of the bike.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
public async Task DoReturn(
|
||||
Bikes.Bike.BluetoothLock.IBikeInfoMutable bike,
|
||||
LocationDto location)
|
||||
LocationDto location,
|
||||
ISmartDevice smartDevice)
|
||||
{
|
||||
if (bike == null)
|
||||
{
|
||||
|
@ -257,7 +259,7 @@ namespace TINK.Model.Connector
|
|||
ReservationCancelReturnResponse l_oResponse;
|
||||
try
|
||||
{
|
||||
l_oResponse = (await CopriServer.DoReturn(bike.Id, location, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
|
||||
l_oResponse = (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -272,8 +274,12 @@ namespace TINK.Model.Connector
|
|||
/// Submits feedback to copri server.
|
||||
/// </summary>
|
||||
/// <param name="userFeedback">Feedback to submit.</param>
|
||||
#if USCSHARP9
|
||||
public async Task DoSubmitFeedback(ICommand.IUserFeedback userFeedback, Uri opertorUri)
|
||||
=> await CopriServer.DoSubmitFeedback(userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
|
||||
|
||||
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
|
||||
#else
|
||||
public async Task DoSubmitFeedback(IUserFeedback userFeedback, Uri opertorUri)
|
||||
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Repository.Request;
|
||||
using TINK.Repository.Request;
|
||||
using TINK.Model.User.Account;
|
||||
using TINK.Model.Device;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -44,9 +45,10 @@ namespace TINK.Model.Connector
|
|||
Task DoBook(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike);
|
||||
|
||||
/// <summary> Request to return a bike.</summary>
|
||||
/// <param name="location">Geolocation of lock when returning bike.</param>
|
||||
/// <param name="bike">Bike to return.</param>
|
||||
Task DoReturn(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto geolocation = null);
|
||||
/// <param name="location">Geolocation of lock when returning bike.</param>
|
||||
/// <param name="smartDevice">Provides info about hard and software.</param>
|
||||
Task DoReturn(Bikes.Bike.BluetoothLock.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
|
||||
|
||||
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
|
||||
bool IsConnected { get; }
|
||||
|
@ -55,12 +57,15 @@ namespace TINK.Model.Connector
|
|||
string SessionCookie { get; }
|
||||
|
||||
Task DoSubmitFeedback(IUserFeedback userFeedback, Uri opertorUri);
|
||||
|
||||
#if USCSHARP9
|
||||
/// <summary>
|
||||
/// Feedback given by user when returning bike.
|
||||
/// </summary>
|
||||
public interface IUserFeedback
|
||||
{
|
||||
/// <summary> Id of the bike to which the feedback is related to.</summary>
|
||||
string BikeId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether bike is broken or not.
|
||||
/// </summary>
|
||||
|
@ -74,12 +79,37 @@ namespace TINK.Model.Connector
|
|||
/// </summary>
|
||||
string Message { get; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>Defines delegate to be raised whenever login state changes.</summary>
|
||||
/// <param name="p_oEventArgs">Holds session cookie and mail address if user logged in successfully.</param>
|
||||
public delegate void LoginStateChangedEventHandler(object p_oSender, LoginStateChangedEventArgs p_oEventArgs);
|
||||
|
||||
#if !USCSHARP9
|
||||
/// <summary>
|
||||
/// Feedback given by user when returning bike.
|
||||
/// </summary>
|
||||
public interface IUserFeedback
|
||||
{
|
||||
/// <summary> Id of the bike to which the feedback is related to.</summary>
|
||||
string BikeId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds whether bike is broken or not.
|
||||
/// </summary>
|
||||
bool IsBikeBroken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds either
|
||||
/// - general feedback
|
||||
/// - error description of broken bike
|
||||
/// or both.
|
||||
/// </summary>
|
||||
string Message { get; }
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary> Event arguments to notify about changes of logged in state.</summary>
|
||||
public class LoginStateChangedEventArgs : EventArgs
|
||||
{
|
||||
|
|
|
@ -1,9 +1,25 @@
|
|||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
#if USCSHARP9
|
||||
public record UserFeedbackDto : ICommand.IUserFeedback
|
||||
{
|
||||
public string BikeId { get; init; }
|
||||
public bool IsBikeBroken { get; init; }
|
||||
public string Message { get; init; }
|
||||
}
|
||||
#else
|
||||
#if USCSHARP9
|
||||
public class UserFeedbackDto : ICommand.IUserFeedback
|
||||
#else
|
||||
public class UserFeedbackDto : IUserFeedback
|
||||
#endif
|
||||
{
|
||||
public string BikeId { get; set; }
|
||||
|
||||
public bool IsBikeBroken { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TINK.Model.Connector.Filter
|
||||
{
|
||||
public static class GroupFilterFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates filter object.
|
||||
/// </summary>
|
||||
/// <param name="group">if value consists
|
||||
/// - list of strings entries are used to filter (intersect) with or if value is
|
||||
/// - null or an empty list null filter is applied, i.e. filtering is off.</param>
|
||||
/// <returns>Filtering object.</returns>
|
||||
/// <remarks>
|
||||
/// Tread group values of null and empty lists as marker to turn filtering off to handle COPRI responses maximal flexible.
|
||||
/// </remarks>
|
||||
public static IGroupFilter Create(IEnumerable<string> group)
|
||||
{
|
||||
return group != null ? (IGroupFilter) new IntersectGroupFilter(group) : new NullGroupFilter();
|
||||
return group != null && group.Count() > 0
|
||||
? (IGroupFilter) new IntersectGroupFilter(group) :
|
||||
new NullGroupFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,29 +86,33 @@ namespace TINK.Model.Connector
|
|||
/// <returns></returns>
|
||||
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
|
||||
{
|
||||
var result = await m_oInnerQuery.GetBikesAndStationsAsync();
|
||||
// Bikes and stations from COPRI or cache
|
||||
var providerBikesAndStations = await m_oInnerQuery.GetBikesAndStationsAsync();
|
||||
|
||||
return new Result<StationsAndBikesContainer>(
|
||||
result.Source,
|
||||
new StationsAndBikesContainer(
|
||||
new StationDictionary(result.Response.StationsAll.CopriVersion, DoFilter(result.Response.StationsAll, Filter)),
|
||||
new BikeCollection(DoFilter(result.Response.Bikes, Filter))),
|
||||
result.Exception);
|
||||
// Do filtering.
|
||||
var filteredStationsDictionary = new StationDictionary(providerBikesAndStations.Response.StationsAll.CopriVersion, DoFilter(providerBikesAndStations.Response.StationsAll, Filter));
|
||||
var filteredBikesDictionary = new BikeCollection(DoFilter(providerBikesAndStations.Response.Bikes, Filter));
|
||||
var filteredBikesAndStations = new Result<StationsAndBikesContainer>(
|
||||
providerBikesAndStations.Source,
|
||||
new StationsAndBikesContainer(filteredStationsDictionary, filteredBikesDictionary),
|
||||
providerBikesAndStations.Exception); ;
|
||||
|
||||
return filteredBikesAndStations;
|
||||
}
|
||||
|
||||
/// <summary> Filter bikes by group. </summary>
|
||||
/// <param name="p_oBikes">Bikes to filter.</param>
|
||||
/// <param name="bikes">Bikes to filter.</param>
|
||||
/// <returns>Filtered bikes.</returns>
|
||||
private static Dictionary<int, BikeInfo> DoFilter(BikeCollection p_oBikes, IGroupFilter filter)
|
||||
private static Dictionary<string, BikeInfo> DoFilter(BikeCollection bikes, IGroupFilter filter)
|
||||
{
|
||||
return p_oBikes.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
|
||||
return bikes.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
|
||||
}
|
||||
|
||||
/// <summary> Filter stations by broup. </summary>
|
||||
/// <returns></returns>
|
||||
private static Dictionary<int, Station.Station> DoFilter(StationDictionary p_oStations, IGroupFilter filter)
|
||||
private static Dictionary<string, IStation> DoFilter(StationDictionary stations, IGroupFilter filter)
|
||||
{
|
||||
return p_oStations.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary((x => x.Id));
|
||||
return stations.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,18 +90,18 @@ namespace TINK.Model.Connector
|
|||
}
|
||||
|
||||
/// <summary> Filter bikes by group. </summary>
|
||||
/// <param name="p_oBikes">Bikes to filter.</param>
|
||||
/// <param name="bikes">Bikes to filter.</param>
|
||||
/// <returns>Filtered bikes.</returns>
|
||||
public static Dictionary<int, BikeInfo> DoFilter(BikeCollection p_oBikes, IEnumerable<string> p_oFilter)
|
||||
public static Dictionary<string, BikeInfo> DoFilter(BikeCollection bikes, IEnumerable<string> filter)
|
||||
{
|
||||
return p_oBikes.Where(x => x.Group.Intersect(p_oFilter).Count() > 0).ToDictionary(x => x.Id);
|
||||
return bikes.Where(x => x.Group.Intersect(filter).Count() > 0).ToDictionary(x => x.Id);
|
||||
}
|
||||
|
||||
/// <summary> Filter stations by broup. </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<int, Station.Station> DoFilter(StationDictionary p_oStations, IEnumerable<string> p_oFilter)
|
||||
public static Dictionary<string, IStation> DoFilter(StationDictionary stations, IEnumerable<string> p_oFilter)
|
||||
{
|
||||
return p_oStations.Where(x => x.Group.Intersect(p_oFilter).Count() > 0).ToDictionary((x => x.Id));
|
||||
return stations.Where(x => x.Group.Intersect(p_oFilter).Count() > 0).ToDictionary(x => x.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
|
@ -70,7 +70,7 @@ namespace TINK.Model.Connector
|
|||
Log.ForContext<CachedQuery>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
|
||||
return new Result<BikeCollection>(
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
await Task.Run(() => new BikeCollection(new Dictionary<int, BikeInfo>())),
|
||||
await Task.Run(() => new BikeCollection(new Dictionary<string, BikeInfo>())),
|
||||
new System.Exception("Abfrage der reservierten/ gebuchten Räder nicht möglich. Kein Benutzer angemeldet."));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
using MonkeyCache.FileStore;
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
@ -31,73 +30,74 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Gets all stations including postions.</summary>
|
||||
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
|
||||
{
|
||||
var resultStations = await server.GetStations();
|
||||
var stationsResponse = await server.GetStations();
|
||||
|
||||
if (resultStations.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| resultStations.Exception != null)
|
||||
if (stationsResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| stationsResponse.Exception != null)
|
||||
{
|
||||
// Stations were read from cache ==> get bikes availbalbe and occupied from cache as well to avoid inconsistencies
|
||||
return new Result<StationsAndBikesContainer>(
|
||||
resultStations.Source,
|
||||
stationsResponse.Source,
|
||||
new StationsAndBikesContainer(
|
||||
resultStations.Response.GetStationsAllMutable(),
|
||||
stationsResponse.Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
(await server.GetBikesAvailable(true)).Response,
|
||||
(await server.GetBikesOccupied(true)).Response,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
resultStations.Exception);
|
||||
stationsResponse.Exception);
|
||||
}
|
||||
|
||||
var l_oBikesAvailableResponse = await server.GetBikesAvailable();
|
||||
if (l_oBikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| l_oBikesAvailableResponse.Exception != null)
|
||||
var bikesAvailableResponse = await server.GetBikesAvailable();
|
||||
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesAvailableResponse.Exception != null)
|
||||
{
|
||||
// Bikes avilable were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies
|
||||
return new Result<StationsAndBikesContainer>(
|
||||
l_oBikesAvailableResponse.Source,
|
||||
bikesAvailableResponse.Source,
|
||||
new StationsAndBikesContainer(
|
||||
(await server.GetStations(true)).Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(l_oBikesAvailableResponse.Response,
|
||||
UpdaterJSON.GetBikesAll(bikesAvailableResponse.Response,
|
||||
(await server.GetBikesOccupied(true)).Response,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
l_oBikesAvailableResponse.Exception);
|
||||
bikesAvailableResponse.Exception);
|
||||
}
|
||||
|
||||
var l_oBikesOccupiedResponse = await server.GetBikesOccupied();
|
||||
if (l_oBikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| l_oBikesOccupiedResponse.Exception != null)
|
||||
var bikesOccupiedResponse = await server.GetBikesOccupied();
|
||||
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|
||||
|| bikesOccupiedResponse.Exception != null)
|
||||
{
|
||||
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
|
||||
return new Result<StationsAndBikesContainer>(
|
||||
l_oBikesOccupiedResponse.Source,
|
||||
bikesOccupiedResponse.Source,
|
||||
new StationsAndBikesContainer(
|
||||
(await server.GetStations(true)).Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
(await server.GetBikesAvailable(true)).Response,
|
||||
l_oBikesOccupiedResponse.Response,
|
||||
bikesOccupiedResponse.Response,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
l_oBikesOccupiedResponse.Exception);
|
||||
bikesOccupiedResponse.Exception);
|
||||
}
|
||||
|
||||
// Both types bikes could read from copri => update cache
|
||||
server.AddToCache(resultStations);
|
||||
server.AddToCache(l_oBikesAvailableResponse);
|
||||
server.AddToCache(l_oBikesOccupiedResponse);
|
||||
server.AddToCache(stationsResponse);
|
||||
server.AddToCache(bikesAvailableResponse);
|
||||
server.AddToCache(bikesOccupiedResponse);
|
||||
|
||||
var exceptions = new[] { resultStations?.Exception, l_oBikesAvailableResponse?.Exception, l_oBikesOccupiedResponse?.Exception }.Where(x => x != null).ToArray();
|
||||
var exceptions = new[] { stationsResponse?.Exception, bikesAvailableResponse?.Exception, bikesOccupiedResponse?.Exception }.Where(x => x != null).ToArray();
|
||||
|
||||
var stationsMutable = stationsResponse.Response.GetStationsAllMutable();
|
||||
var bikesMutable = UpdaterJSON.GetBikesAll(
|
||||
bikesAvailableResponse.Response,
|
||||
bikesOccupiedResponse.Response,
|
||||
Mail,
|
||||
DateTimeProvider);
|
||||
|
||||
return new Result<StationsAndBikesContainer>(
|
||||
resultStations.Source,
|
||||
new StationsAndBikesContainer(
|
||||
resultStations.Response.GetStationsAllMutable(),
|
||||
UpdaterJSON.GetBikesAll(
|
||||
l_oBikesAvailableResponse.Response,
|
||||
l_oBikesOccupiedResponse.Response,
|
||||
Mail,
|
||||
DateTimeProvider)),
|
||||
stationsResponse.Source,
|
||||
new StationsAndBikesContainer(stationsMutable, bikesMutable),
|
||||
exceptions.Length > 0 ? new AggregateException(exceptions) : null);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
|
@ -44,7 +44,7 @@ namespace TINK.Model.Connector
|
|||
Log.ForContext<Query>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
|
||||
return new Result<BikeCollection>(
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
await Task.Run(() => new BikeCollection(new Dictionary<int, BikeInfo>())),
|
||||
await Task.Run(() => new BikeCollection(new Dictionary<string, BikeInfo>())),
|
||||
new System.Exception("Abfrage der reservierten/ gebuchten Räder fehlgeschlagen. Kein Benutzer angemeldet."));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using System.Threading.Tasks;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Services.CopriApi;
|
||||
using TINK.Model.Repository;
|
||||
using TINK.Repository;
|
||||
|
||||
namespace TINK.Model.Connector
|
||||
{
|
||||
|
|
|
@ -5,8 +5,8 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Repository.Exception;
|
||||
using TINK.Model.Repository.Response;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using TINK.Model.State;
|
||||
|
||||
|
@ -51,14 +51,16 @@ namespace TINK.Model.Connector
|
|||
/// <summary> Gets the position from StationInfo object. </summary>
|
||||
/// <param name="p_oAuthorizationResponse">Object to get information from.</param>
|
||||
/// <returns>Position information.</returns>
|
||||
public static IEnumerable<string> GetGroup(this string p_oGroup)
|
||||
public static IEnumerable<string> GetGroup(this string[] group)
|
||||
{
|
||||
if (string.IsNullOrEmpty(p_oGroup))
|
||||
if (group == null || group.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Can not get goup form string. Group text can not be null.");
|
||||
// If not logged in stations groups are empty form COPRI version v4.1.
|
||||
Log.Debug("Can not get goup form string. Group text can not be null.");
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
return new HashSet<string>(p_oGroup.Split(',')).ToList();
|
||||
return new HashSet<string>(group).ToList();
|
||||
}
|
||||
|
||||
/// <summary> Gets the position from StationInfo object. </summary>
|
||||
|
@ -78,9 +80,9 @@ namespace TINK.Model.Connector
|
|||
{
|
||||
return p_oStationInfo.station_group.GetGroup();
|
||||
}
|
||||
catch (System.Exception l_oException)
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
throw new System.Exception($"Can not get group of stations from text \"{p_oStationInfo.station_group}\".", l_oException);
|
||||
throw new Exception($"Can not get group of stations from text \"{p_oStationInfo.station_group}\".", l_oException);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,24 +312,19 @@ namespace TINK.Model.Connector
|
|||
/// </summary>
|
||||
/// <param name="p_strGps">Text to extract positon from.</param>
|
||||
/// <returns>Position object.</returns>
|
||||
public static Station.Position GetPosition(string p_strGps)
|
||||
public static Station.Position GetPosition(GpsInfo gps)
|
||||
{
|
||||
if (p_strGps == null)
|
||||
if (gps == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var l_oPosition = p_strGps.Split(',');
|
||||
|
||||
if (l_oPosition.Length != 2)
|
||||
return null;
|
||||
|
||||
double l_oLatitude;
|
||||
if (!double.TryParse(l_oPosition[0], NumberStyles.Float, CultureInfo.InvariantCulture, out l_oLatitude))
|
||||
if (!double.TryParse(gps.latitude, NumberStyles.Float, CultureInfo.InvariantCulture, out l_oLatitude))
|
||||
return null;
|
||||
|
||||
double l_oLongitude;
|
||||
if (!double.TryParse(l_oPosition[1], NumberStyles.Float, CultureInfo.InvariantCulture, out l_oLongitude))
|
||||
if (!double.TryParse(gps.longitude, NumberStyles.Float, CultureInfo.InvariantCulture, out l_oLongitude))
|
||||
return null;
|
||||
|
||||
return new Station.Position(l_oLatitude, l_oLongitude);
|
||||
|
@ -354,5 +351,15 @@ namespace TINK.Model.Connector
|
|||
? new Uri($"{bikeInfo.uri_operator}/{CopriServerUriList.REST_RESOURCE_ROOT}")
|
||||
: null;
|
||||
}
|
||||
|
||||
/// <summary> Gets the copriversion from.</summary>
|
||||
/// <param name="response">Response to get version info from.</param>
|
||||
/// <returns>COPRI version</returns>
|
||||
public static Version GetCopriVersion(this CopriVersion response)
|
||||
=> response!= null
|
||||
&& !string.IsNullOrEmpty(response.copri_version)
|
||||
&& Version.TryParse(response.copri_version, out Version copriVersion)
|
||||
? copriVersion
|
||||
: throw new InvalidResponseException($"Can not get version info from copri response {response?.copri_version}.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using System;
|
||||
using TINK.Model.Bike;
|
||||
using TINK.Model.Station;
|
||||
using TINK.Model.Repository.Response;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Model.User.Account;
|
||||
using System.Collections.Generic;
|
||||
using TINK.Model.State;
|
||||
using TINK.Model.Repository.Exception;
|
||||
using TINK.Repository.Exception;
|
||||
using Serilog;
|
||||
|
||||
using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
|
||||
|
@ -190,8 +190,8 @@ namespace TINK.Model.Connector
|
|||
string p_strMail,
|
||||
Func<DateTime> p_oDateTimeProvider)
|
||||
{
|
||||
var l_oBikesDictionary = new Dictionary<int, BikeInfo>();
|
||||
var l_oDuplicates = new Dictionary<int, BikeInfo>();
|
||||
var l_oBikesDictionary = new Dictionary<string, BikeInfo>();
|
||||
var l_oDuplicates = new Dictionary<string, BikeInfo>();
|
||||
|
||||
// Get bikes from Copri/ file/ memory, ....
|
||||
if (p_oBikesAvailableResponse != null
|
||||
|
@ -295,7 +295,7 @@ namespace TINK.Model.Connector
|
|||
return null;
|
||||
}
|
||||
|
||||
if (bikeInfo.station == null)
|
||||
if (string.IsNullOrEmpty(bikeInfo.station))
|
||||
{
|
||||
// Bike available must always have a station id because bikes can only be returned at a station.
|
||||
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. No station info set.");
|
||||
|
@ -485,7 +485,11 @@ namespace TINK.Model.Connector
|
|||
return new Bikes.Bike.TariffDescription
|
||||
{
|
||||
Name = tariffDesciption?.name,
|
||||
#if USCSHARP9
|
||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
|
||||
#else
|
||||
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?) null,
|
||||
#endif
|
||||
FreeTimePerSession = double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours) ? TimeSpan.FromHours(freeHours) : TimeSpan.Zero,
|
||||
FeeEuroPerHour = double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour) ? euroPerHour : double.NaN,
|
||||
AboEuroPerMonth = double.TryParse(tariffDesciption?.abo_eur_per_month, NumberStyles.Any, CultureInfo.InvariantCulture, out double aboEuroPerMonth) ? aboEuroPerMonth : double.NaN,
|
||||
|
|
21
TINKLib/Model/Device/ISmartDevice.cs
Normal file
21
TINKLib/Model/Device/ISmartDevice.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace TINK.Model.Device
|
||||
{
|
||||
public interface ISmartDevice
|
||||
{
|
||||
/// <summary> Gets unitque device identifier. </summary>
|
||||
/// <returns>Gets the identifies specifying device.</returns>
|
||||
string Identifier { get; }
|
||||
|
||||
/// <summary> Manufacturer (Samsung). </summary>
|
||||
string Manufacturer { get; }
|
||||
|
||||
/// <summary> Device Model (SMG-950U, iPhone10,6). </summary>
|
||||
string Model { get; }
|
||||
|
||||
/// <summary> Platform (Android). </summary>
|
||||
string PlatformText { get; }
|
||||
|
||||
/// <summary> Operating System Version Number (7.0) as text</summary>
|
||||
string VersionText { get; }
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
using Plugin.Permissions.Abstractions;
|
||||
using Serilog.Events;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using TINK.Model.Connector;
|
||||
using TINK.Model.Device;
|
||||
using TINK.Services.BluetoothLock;
|
||||
using TINK.Model.Services.CopriApi.ServerUris;
|
||||
using TINK.Model.Services.Geolocation;
|
||||
using TINK.Settings;
|
||||
using TINK.ViewModel.Map;
|
||||
using TINK.ViewModel.Settings;
|
||||
using TINK.Services;
|
||||
using TINK.Model.Station;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ namespace TINK.Model
|
|||
IFilteredConnector GetConnector(bool isConnected);
|
||||
|
||||
/// <summary> Name of the station which is selected. </summary>
|
||||
int? SelectedStation { get; set; }
|
||||
IStation SelectedStation { get; set; }
|
||||
|
||||
/// <summary>Polling periode.</summary>
|
||||
PollingParameters Polling { get; set; }
|
||||
|
@ -67,6 +67,10 @@ namespace TINK.Model
|
|||
/// <summary> Gets the minimum logging level. </summary>
|
||||
LogEventLevel MinimumLogEventLevel { get; set; }
|
||||
|
||||
/// <summary> Gets a value indicating whether reporting level is verbose or not.</summary>
|
||||
bool IsReportLevelVerbose { get; set; }
|
||||
|
||||
|
||||
/// <summary> Updates logging level. </summary>
|
||||
/// <param name="p_oNewLevel">New level to set.</param>
|
||||
void UpdateLoggingLevel(LogEventLevel p_oNewLevel);
|
||||
|
@ -77,22 +81,19 @@ namespace TINK.Model
|
|||
/// <summary> Holds the different lock service implementations.</summary>
|
||||
LocksServicesContainerMutable LocksServices { get; }
|
||||
|
||||
/// <summary> Holds the different geo location service implementations.</summary>
|
||||
ServicesContainerMutable<IGeolocation> GeolocationServices { get; }
|
||||
|
||||
/// <summary> Holds available app themes.</summary>
|
||||
ServicesContainerMutable<object> Themes { get; }
|
||||
|
||||
/// <summary> Reference of object which provides device information. </summary>
|
||||
IDevice Device { get; }
|
||||
|
||||
/// <summary> Os permission.</summary>
|
||||
IPermissions Permissions { get; }
|
||||
ISmartDevice SmartDevice { get; }
|
||||
|
||||
/// <summary> Holds the folder where settings files are stored. </summary>
|
||||
string SettingsFileFolder { get; }
|
||||
|
||||
/// <summary> Holds the external path. </summary>
|
||||
string ExternalFolder { get; }
|
||||
|
||||
/// <summary> Holds the stations availalbe. </summary>
|
||||
IEnumerable<IStation> Stations {get; set;}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using TINK.Model.Repository.Exception;
|
||||
using TINK.Repository.Exception;
|
||||
|
||||
namespace TINK.Model.Logging
|
||||
{
|
||||
|
|
|
@ -18,61 +18,61 @@ namespace TINK.Model.Logging
|
|||
public static class LoggerConfigurationHelper
|
||||
{
|
||||
/// <summary> Holds the log file name. </summary>
|
||||
private static ILoggingDirectoryManager m_oDirectoryManager = new EmptyDirectoryLoggingManger();
|
||||
private static ILoggingDirectoryManager DirectoryManager { get; set; } = new EmptyDirectoryLoggingManger();
|
||||
|
||||
/// <summary> Sets up logging to file.</summary>
|
||||
/// <param name="p_oLoggerConfiguration">Object to set up logging with.</param>
|
||||
/// <param name="loggerConfiguration">Object to set up logging with.</param>
|
||||
/// <param name="p_oDevice">Object to get file informaton from.</param>
|
||||
/// <param name="p_oRollingInterval">Specifies rolling type.</param>
|
||||
/// <param name="p_iRetainedFilesCountLimit">Count of file being retained.</param>
|
||||
/// <param name="rollingInterval">Specifies rolling type.</param>
|
||||
/// <param name="retainedFilesCountLimit">Count of file being retained.</param>
|
||||
/// <returns>Logger object.</returns>
|
||||
public static LoggerConfiguration File(
|
||||
this LoggerSinkConfiguration p_oLoggerConfiguration,
|
||||
string p_strLogFileFolder,
|
||||
RollingInterval p_oRollingInterval = RollingInterval.Session,
|
||||
int p_iRetainedFilesCountLimit = 10)
|
||||
this LoggerSinkConfiguration loggerConfiguration,
|
||||
string logFileFolder,
|
||||
RollingInterval rollingInterval = RollingInterval.Session,
|
||||
int retainedFilesCountLimit = 10)
|
||||
{
|
||||
if (m_oDirectoryManager is EmptyDirectoryLoggingManger)
|
||||
if (DirectoryManager is EmptyDirectoryLoggingManger)
|
||||
{
|
||||
// Roll file only once per app session.
|
||||
try
|
||||
{
|
||||
m_oDirectoryManager = new LoggingDirectoryManager(
|
||||
DirectoryManager = new LoggingDirectoryManager(
|
||||
Directory.GetFiles,
|
||||
Directory.Exists,
|
||||
(path) => Directory.CreateDirectory(path),
|
||||
System.IO.File.Delete,
|
||||
p_strLogFileFolder,
|
||||
logFileFolder,
|
||||
Path.DirectorySeparatorChar,
|
||||
p_iRetainedFilesCountLimit);
|
||||
retainedFilesCountLimit);
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
Log.Error("Log directory manager could not be instanciated successfully. {@l_oException}", l_oException);
|
||||
m_oDirectoryManager = new EmptyDirectoryLoggingManger();
|
||||
DirectoryManager = new EmptyDirectoryLoggingManger();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_oDirectoryManager.DeleteObsoleteLogs();
|
||||
DirectoryManager.DeleteObsoleteLogs();
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
Log.Error("Not all obsolte log files could be deleted successfully. {@l_oException}", l_oException);
|
||||
}
|
||||
|
||||
if (p_oLoggerConfiguration == null)
|
||||
if (loggerConfiguration == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return p_oLoggerConfiguration.File(
|
||||
return loggerConfiguration.File(
|
||||
new JsonFormatter(),
|
||||
m_oDirectoryManager.LogFileName,
|
||||
DirectoryManager.LogFileName,
|
||||
/*shared: true, // Leads to exception if activated.*/
|
||||
rollingInterval: Serilog.RollingInterval.Infinite,
|
||||
retainedFileCountLimit: p_iRetainedFilesCountLimit);
|
||||
retainedFileCountLimit: retainedFilesCountLimit);
|
||||
}
|
||||
|
||||
/// <summary> Gets all log files in logging directory. </summary>
|
||||
|
@ -82,7 +82,7 @@ namespace TINK.Model.Logging
|
|||
{
|
||||
try
|
||||
{
|
||||
return m_oDirectoryManager.GetLogFiles();
|
||||
return DirectoryManager.GetLogFiles();
|
||||
}
|
||||
catch (Exception l_oException)
|
||||
{
|
||||
|
@ -97,7 +97,7 @@ namespace TINK.Model.Logging
|
|||
public static string GetLogFilePath(
|
||||
this ILogger p_oLogger)
|
||||
{
|
||||
return m_oDirectoryManager.LogFilePath;
|
||||
return DirectoryManager.LogFilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace TINK.Model.Logging
|
|||
|
||||
if (string.IsNullOrEmpty(LogFileTitle))
|
||||
{
|
||||
LogFileTitle = $"{ DateTime.Now:yyyy_MM_dd_HH_mm_ss}.jsnl";
|
||||
LogFileTitle = $"{DateTime.Now:yyyy_MM_dd_HH_mm_ss}.jsnl";
|
||||
}
|
||||
|
||||
// Create directory if direcotry does not exist.
|
||||
|
@ -74,7 +74,6 @@ namespace TINK.Model.Logging
|
|||
|
||||
throw new FileOperationException($"Logging directory {LogFilePath} could not be created successfully.", l_oException);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@ namespace TINK.Model.Settings
|
|||
/// <summary> Key of the logging level entry. </summary>
|
||||
public const string MINLOGGINGLEVELKEY = "MinimumLoggingLevel";
|
||||
|
||||
/// <summary> Key of the logging level entry. </summary>
|
||||
public const string ISREPORTLEVELVERBOSEKEY = "IsReportLevelVerbose";
|
||||
|
||||
/// <summary> Key of the center to ... entry. </summary>
|
||||
public const string CENTERMAPTOCURRENTLOCATION = "CenterMapToCurrentLocation";
|
||||
|
||||
|
@ -273,6 +276,16 @@ namespace TINK.Model.Settings
|
|||
return (LogEventLevel)int.Parse(JsonConvert.DeserializeObject<string>(l_strLevel));
|
||||
}
|
||||
|
||||
/// <summary> Gets a value indicating whether report level is verbose or not.</summary>
|
||||
/// <param name="settingsJSON">Dictionary to get value from.</param>
|
||||
public static bool? GetIsReportLevelVerbose(Dictionary<string, string> settingsJSON) => GetNullableEntry<bool>(ISREPORTLEVELVERBOSEKEY, settingsJSON);
|
||||
|
||||
/// <summary> Sets a value indicating whether report level is verbose or not.</summary>
|
||||
/// <param name="p_oSettingsJSON">Dictionary to get value from.</param>
|
||||
public static Dictionary<string, string> SetIsReportLevelVerbose(this IDictionary<string, string> targetDictionary, bool isReportLevelVerbose)
|
||||
=> SetEntry(isReportLevelVerbose, ISREPORTLEVELVERBOSEKEY, targetDictionary);
|
||||
|
||||
|
||||
/// <summary> Sets the logging level.</summary>
|
||||
/// <param name="p_oSettingsJSON">Dictionary to get logging level from.</param>
|
||||
public static Dictionary<string, string> SetMinimumLoggingLevel(this IDictionary<string, string> p_oTargetDictionary, LogEventLevel p_oLevel)
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace TINK.Model.Settings
|
|||
{
|
||||
public const LogEventLevel DEFAULTLOGGINLEVEL = LogEventLevel.Error;
|
||||
|
||||
public const bool DEFAULTREPOTLEVEL = false;
|
||||
|
||||
// Default value of the expires after entry. Controls the expiration time of the cache values.
|
||||
private TimeSpan DEFAULTEXPIRESAFTER = TimeSpan.FromSeconds(1);
|
||||
|
||||
|
@ -24,6 +26,7 @@ namespace TINK.Model.Settings
|
|||
/// <param name="activeUri"></param>
|
||||
/// <param name="pollingParameters"></param>
|
||||
/// <param name="minimumLogEventLevel">Minimum logging level to be applied.</param>
|
||||
/// <param name="isReportLevelVerbose">True if logging level is verbose.</param>
|
||||
/// <param name="expiresAfter">Holds the expires after value.</param>
|
||||
/// <param name="activeLockService">Gets the name of the lock service to use.</param>
|
||||
/// <param name="connectTimeout">Timeout to apply when connecting to bluetooth lock</param>
|
||||
|
@ -34,6 +37,7 @@ namespace TINK.Model.Settings
|
|||
Uri activeUri = null,
|
||||
PollingParameters pollingParameters = null,
|
||||
LogEventLevel? minimumLogEventLevel = null,
|
||||
bool? isReportLevelVerbose = null,
|
||||
TimeSpan? expiresAfter = null,
|
||||
string activeLockService = null,
|
||||
TimeSpan? connectTimeout = null,
|
||||
|
@ -48,6 +52,7 @@ namespace TINK.Model.Settings
|
|||
ActiveUri = GetActiveUri(activeUri);
|
||||
PollingParameters = pollingParameters ?? PollingParameters.Default;
|
||||
MinimumLogEventLevel = minimumLogEventLevel ?? DEFAULTLOGGINLEVEL;
|
||||
IsReportLevelVerbose = isReportLevelVerbose ?? DEFAULTREPOTLEVEL;
|
||||
ExpiresAfter = expiresAfter ?? DEFAULTEXPIRESAFTER;
|
||||
ActiveLockService = activeLockService ?? LocksServicesContainerMutable.DefaultLocksservice;
|
||||
ConnectTimeout = connectTimeout ?? new TimeSpan(0, 0, TimeOutProvider.DEFAULT_BLUETOOTHCONNECT_TIMEOUTSECONDS); // Try one sec. to connect.
|
||||
|
@ -93,6 +98,9 @@ namespace TINK.Model.Settings
|
|||
|
||||
public string ActiveTheme { get; }
|
||||
|
||||
/// <summary> Gets a value indicating whether reporting level is verbose or not.</summary>
|
||||
public bool IsReportLevelVerbose { get; }
|
||||
|
||||
public static Uri GetActiveUri(Uri activeUri) => activeUri ?? Services.CopriApi.ServerUris.CopriServerUriList.DefaultActiveUri;
|
||||
|
||||
public static bool GetCenterMapToCurrentLocation(Uri activeUri)
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace TINK.Model.Station
|
|||
public interface IStation
|
||||
{
|
||||
/// <summary> Holds the unique id of the station.c</summary>
|
||||
int Id { get; }
|
||||
string Id { get; }
|
||||
|
||||
/// <summary> Holds the group to which the station belongs.</summary>
|
||||
IEnumerable<string> Group { get; }
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace TINK.Model.Station
|
|||
public class NullStation : IStation
|
||||
{
|
||||
/// <summary> Holds the unique id of the station.c</summary>
|
||||
public int Id => -1;
|
||||
public string Id => null;
|
||||
|
||||
/// <summary> Holds the group to which the station belongs.</summary>
|
||||
public IEnumerable<string> Group => new List<string>();
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace TINK.Model.Station
|
|||
/// <param name="p_oPosition">GPS- position of the station.</param>
|
||||
/// <param name="p_strStationName">Name of the station.</param>
|
||||
public Station(
|
||||
int p_iId,
|
||||
string p_iId,
|
||||
IEnumerable<string> p_oGroup,
|
||||
Position p_oPosition,
|
||||
string p_strStationName = "")
|
||||
|
@ -24,7 +24,7 @@ namespace TINK.Model.Station
|
|||
}
|
||||
|
||||
/// <summary> Holds the unique id of the station.c</summary>
|
||||
public int Id { get; }
|
||||
public string Id { get; }
|
||||
|
||||
/// <summary> Holds the group to which the station belongs.</summary>
|
||||
public IEnumerable<string> Group { get; }
|
||||
|
|
|
@ -4,10 +4,10 @@ using System.Collections.Generic;
|
|||
|
||||
namespace TINK.Model.Station
|
||||
{
|
||||
public class StationDictionary : IEnumerable<Station>
|
||||
public class StationDictionary : IEnumerable<IStation>
|
||||
{
|
||||
/// <summary> Holds the list of stations. </summary>
|
||||
private readonly IDictionary<int, Station> m_oStationDictionary;
|
||||
private readonly IDictionary<string, IStation> m_oStationDictionary;
|
||||
|
||||
/// <summary> Count of stations. </summary>
|
||||
public int Count { get { return m_oStationDictionary.Count; } }
|
||||
|
@ -16,16 +16,16 @@ namespace TINK.Model.Station
|
|||
|
||||
/// <summary> Constructs a station dictionary object. </summary>
|
||||
/// <param name="p_oVersion">Version of copri- service.</param>
|
||||
public StationDictionary(Version p_oVersion = null, IDictionary<int, Station> p_oStations = null)
|
||||
public StationDictionary(Version p_oVersion = null, IDictionary<string, IStation> p_oStations = null)
|
||||
{
|
||||
m_oStationDictionary = p_oStations ?? new Dictionary<int, Station>();
|
||||
m_oStationDictionary = p_oStations ?? new Dictionary<string, IStation>();
|
||||
|
||||
CopriVersion = p_oVersion != null
|
||||
? new Version(p_oVersion.Major, p_oVersion.Minor, p_oVersion.Revision, p_oVersion.Build)
|
||||
: new Version(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public IEnumerator<Station> GetEnumerator()
|
||||
public IEnumerator<IStation> GetEnumerator()
|
||||
{
|
||||
return m_oStationDictionary.Values.GetEnumerator();
|
||||
}
|
||||
|
@ -33,41 +33,41 @@ namespace TINK.Model.Station
|
|||
/// <summary>
|
||||
/// Deteermines whether a station by given key exists.
|
||||
/// </summary>
|
||||
/// <param name="p_strKey">Key to check.</param>
|
||||
/// <param name="key">Key to check.</param>
|
||||
/// <returns>True if station exists.</returns>
|
||||
public bool ContainsKey(int p_strKey)
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return m_oStationDictionary.ContainsKey(p_strKey);
|
||||
return m_oStationDictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a station by station id.
|
||||
/// </summary>
|
||||
/// <param name="p_iId"></param>
|
||||
public void RemoveById(int p_iId)
|
||||
/// <param name="id"></param>
|
||||
public void RemoveById(string id)
|
||||
{
|
||||
if (!m_oStationDictionary.ContainsKey(p_iId))
|
||||
if (!m_oStationDictionary.ContainsKey(id))
|
||||
{
|
||||
// Nothing to do if there is no station with given name.
|
||||
return;
|
||||
}
|
||||
|
||||
m_oStationDictionary.Remove(p_iId);
|
||||
m_oStationDictionary.Remove(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a station by station name.
|
||||
/// </summary>
|
||||
/// <param name="p_iId"></param>
|
||||
public Station GetById(int p_iId)
|
||||
/// <param name="id"></param>
|
||||
public IStation GetById(string id)
|
||||
{
|
||||
if (!m_oStationDictionary.ContainsKey(p_iId))
|
||||
if (!m_oStationDictionary.ContainsKey(id))
|
||||
{
|
||||
// Nothing to do if there is no station with given name.
|
||||
return null;
|
||||
}
|
||||
|
||||
return m_oStationDictionary[p_iId];
|
||||
return m_oStationDictionary[id];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -22,6 +22,7 @@ using TINK.ViewModel.Settings;
|
|||
using TINK.Services;
|
||||
using TINK.Services.BluetoothLock.BLE;
|
||||
using Xamarin.Forms;
|
||||
using TINK.Model.Station;
|
||||
|
||||
namespace TINK.Model
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ namespace TINK.Model
|
|||
/// <returns>True if setting credentials succeeded.</returns>
|
||||
public delegate bool SetCredentialsDelegate(string p_strMailAddress, string p_strPassword);
|
||||
|
||||
/// <summary>Returns the id of the app to be identified by copri.</summary>
|
||||
/// <summary>Returns the id of the app (sharee.bike) to be identified by copri.</summary>
|
||||
public static string MerchantId => "oiF2kahH";
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,6 +68,9 @@ namespace TINK.Model
|
|||
/// <summary> Gets the minimum logging level. </summary>
|
||||
public LogEventLevel MinimumLogEventLevel { get; set; }
|
||||
|
||||
/// <summary> Gets a value indicating whether reporting level is verbose or not.</summary>
|
||||
public bool IsReportLevelVerbose { get; set; }
|
||||
|
||||
/// <summary> Holds the uri which is applied after restart. </summary>
|
||||
public Uri NextActiveUri { get; set; }
|
||||
|
||||
|
@ -81,6 +85,7 @@ namespace TINK.Model
|
|||
.SetGroupFilterSettings(FilterGroupSetting)
|
||||
.SetAppVersion(AppVersion)
|
||||
.SetMinimumLoggingLevel(MinimumLogEventLevel)
|
||||
.SetIsReportLevelVerbose(IsReportLevelVerbose)
|
||||
.SetExpiresAfter(ExpiresAfter)
|
||||
.SetWhatsNew(AppVersion)
|
||||
.SetActiveLockService(LocksServices.Active.GetType().FullName)
|
||||
|
@ -115,7 +120,11 @@ namespace TINK.Model
|
|||
/// <summary>
|
||||
/// Holds the default polling value.
|
||||
/// </summary>
|
||||
#if USCSHARP9
|
||||
public TimeSpan DefaultPolling => new (0, 0, 10);
|
||||
#else
|
||||
public TimeSpan DefaultPolling => new TimeSpan(0, 0, 10);
|
||||
#endif
|
||||
|
||||
/// <summary> Constructs TinkApp object. </summary>
|
||||
/// <param name="settings"></param>
|
||||
|
@ -139,10 +148,9 @@ namespace TINK.Model
|
|||
Settings.Settings settings,
|
||||
IStore accountStore,
|
||||
Func<bool, Uri, string, string, TimeSpan, IConnector> connectorFactory,
|
||||
IGeolocation geolocationService,
|
||||
IGeolodationDependent geolodationServiceDependent,
|
||||
IServicesContainer<IGeolocation> geolocationServicesContainer,
|
||||
ILocksService locksService,
|
||||
IDevice device,
|
||||
ISmartDevice device,
|
||||
ISpecialFolder specialFolder,
|
||||
ICipher cipher,
|
||||
IPermissions permissions = null,
|
||||
|
@ -188,16 +196,8 @@ namespace TINK.Model
|
|||
new HashSet<object> { new Themes.Konrad() , new Themes.ShareeBike() },
|
||||
settings.ActiveTheme);
|
||||
|
||||
GeolocationServices = new ServicesContainerMutable<IGeolocation>(
|
||||
geolocationService == null
|
||||
? new HashSet<IGeolocation> { new LastKnownGeolocationService(geolodationServiceDependent), new SimulatedGeolocationService(geolodationServiceDependent), new GeolocationService(geolodationServiceDependent) }
|
||||
: new HashSet<IGeolocation> { geolocationService },
|
||||
geolocationService == null
|
||||
? (lastVersion >= new Version(3, 0, 173) ? settings.ActiveGeolocationService : typeof(LastKnownGeolocationService).FullName)
|
||||
: geolocationService.GetType().FullName);
|
||||
|
||||
// Load filters from settings or apply defaults if no settings are available
|
||||
var l_oAccount = accountStore.Load();
|
||||
GeolocationServices = geolocationServicesContainer
|
||||
?? throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. No geolocation services container object available.");
|
||||
|
||||
if (settings.ActiveUri == new Uri(CopriServerUriList.TINK_LIVE) ||
|
||||
settings.ActiveUri == new Uri(CopriServerUriList.TINK_DEVEL))
|
||||
|
@ -217,7 +217,7 @@ namespace TINK.Model
|
|||
|
||||
CenterMapToCurrentLocation = settings.CenterMapToCurrentLocation;
|
||||
|
||||
Device = device
|
||||
SmartDevice = device
|
||||
?? throw new ArgumentException("Can not instantiate TinkApp- object. No device information provider available.");
|
||||
|
||||
if (specialFolder == null)
|
||||
|
@ -236,12 +236,10 @@ namespace TINK.Model
|
|||
|
||||
SettingsFileFolder = specialFolder.GetInternalPersonalDir();
|
||||
|
||||
SelectedStation = null;
|
||||
|
||||
ActiveUser = new User.User(
|
||||
accountStore,
|
||||
l_oAccount,
|
||||
device.GetIdentifier());
|
||||
accountStore.GetType().Name == "StoreLegacy" ? new Store() : accountStore,
|
||||
accountStore.Load().Result,
|
||||
device.Identifier);
|
||||
|
||||
this.isConnectedFunc = isConnectedFunc ?? (() => CrossConnectivity.Current.IsConnected);
|
||||
|
||||
|
@ -249,7 +247,7 @@ namespace TINK.Model
|
|||
|
||||
// Create filtered connector for offline mode.
|
||||
m_oConnector = FilteredConnectorFactory.Create(
|
||||
FilterGroupSetting.DoFilter(l_oAccount.DoFilter(GroupFilterMapPage.DoFilter())),
|
||||
FilterGroupSetting.DoFilter(GroupFilterMapPage.DoFilter()),
|
||||
ConnectorFactory(GetIsConnected(), settings.ActiveUri, ActiveUser.SessionCookie, ActiveUser.Mail, ExpiresAfter));
|
||||
|
||||
// Get uris from file.
|
||||
|
@ -266,8 +264,7 @@ namespace TINK.Model
|
|||
|
||||
MinimumLogEventLevel = settings.MinimumLogEventLevel;
|
||||
|
||||
Permissions = permissions ??
|
||||
throw new ArgumentException("Can not instantiate TinkApp- object. Permissions object must never be null.");
|
||||
IsReportLevelVerbose = settings.IsReportLevelVerbose;
|
||||
|
||||
WhatsNew = new WhatsNew(AppVersion, lastVersion, whatsNewShownInVersion);
|
||||
|
||||
|
@ -299,13 +296,10 @@ namespace TINK.Model
|
|||
public User.User ActiveUser { get; }
|
||||
|
||||
/// <summary> Reference of object which provides device information. </summary>
|
||||
public IDevice Device { get; }
|
||||
|
||||
/// <summary> Os permission.</summary>
|
||||
public IPermissions Permissions { get; }
|
||||
public ISmartDevice SmartDevice { get; }
|
||||
|
||||
/// <summary> Holds delegate to determine whether device is connected or not.</summary>
|
||||
private Func<bool> isConnectedFunc;
|
||||
private readonly Func<bool> isConnectedFunc;
|
||||
|
||||
/// <summary> Gets whether device is connected to internet or not. </summary>
|
||||
public bool GetIsConnected() => isConnectedFunc();
|
||||
|
@ -328,13 +322,16 @@ namespace TINK.Model
|
|||
public ICipher Cipher { get; }
|
||||
|
||||
/// <summary> Name of the station which is selected. </summary>
|
||||
public int? SelectedStation { get; set; }
|
||||
public IStation SelectedStation { get; set; } = new Station.Station(null, new List<string>(), null);
|
||||
|
||||
/// <summary> Holds the stations availalbe. </summary>
|
||||
public IEnumerable<IStation> Stations { get; set; } = new List<Station.Station>();
|
||||
|
||||
/// <summary> Action to post to GUI thread.</summary>
|
||||
public Action<SendOrPostCallback, object> PostAction { get; }
|
||||
|
||||
/// <summary> Function which creates a connector depending on connected status.</summary>
|
||||
private Func<bool, Uri, string, string, TimeSpan, IConnector> ConnectorFactory { get; }
|
||||
private Func<bool, Uri, string /*userAgent*/, string /*sessionCookie*/, TimeSpan, IConnector> ConnectorFactory { get; }
|
||||
|
||||
/// <summary> Holds the object which provides offline data.</summary>
|
||||
private IFilteredConnector m_oConnector;
|
||||
|
@ -362,14 +359,11 @@ namespace TINK.Model
|
|||
return m_oConnector;
|
||||
}
|
||||
|
||||
/// <summary> Query geolocation. </summary>
|
||||
public IGeolocation Geolocation => GeolocationServices.Active;
|
||||
|
||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||
public LocksServicesContainerMutable LocksServices { get; set; }
|
||||
|
||||
/// <summary> Holds available app themes.</summary>
|
||||
public ServicesContainerMutable<IGeolocation> GeolocationServices { get; }
|
||||
public IServicesContainer<IGeolocation> GeolocationServices { get; }
|
||||
|
||||
/// <summary> Manages the different types of LocksService objects.</summary>
|
||||
public ServicesContainerMutable<object> Themes { get; }
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace TINK.Model.User.Account
|
|||
PickLoggingLevel = 64, // Allows to select the logging level.
|
||||
ShowDiagnostics = 128, // Turns on display of diagnostics.
|
||||
SwitchNoSiteCaching = 1024, // Allows to turn off/ on caching of sites displayed in app hosted by COPRI
|
||||
ReportLevel = 2048, // Allows extent to show error messages.
|
||||
All = PickCopriServer +
|
||||
ManageCopriCacheExpiration +
|
||||
ManagePolling +
|
||||
|
@ -24,7 +25,8 @@ namespace TINK.Model.User.Account
|
|||
PickLocationServiceImplementation +
|
||||
PickLoggingLevel +
|
||||
ShowDiagnostics +
|
||||
SwitchNoSiteCaching,
|
||||
SwitchNoSiteCaching +
|
||||
ReportLevel,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -48,24 +50,24 @@ namespace TINK.Model.User.Account
|
|||
public class Account : IAccount
|
||||
{
|
||||
/// <summary> Constructs an account object.</summary>
|
||||
/// <param name="p_oMail">Mail addresss.</param>
|
||||
/// <param name="p_Pwd">Password.</param>
|
||||
/// <param name="p_oSessionCookie">Session cookie from copri.</param>
|
||||
/// <param name="p_strGroup">Group holdig info about Group (TINK, Konrad, ...)</param>
|
||||
/// <param name="mail">Mail addresss.</param>
|
||||
/// <param name="password">Password.</param>
|
||||
/// <param name="sessionCookie">Session cookie from copri.</param>
|
||||
/// <param name="group">Group holdig info about Group (TINK, Konrad, ...)</param>
|
||||
/// <param name="p_iDebugLevel">Flag which controls display of debug settings.</param>
|
||||
public Account(
|
||||
string p_oMail,
|
||||
string p_Pwd,
|
||||
string p_oSessionCookie,
|
||||
IEnumerable<string> p_strGroup,
|
||||
string mail,
|
||||
string password,
|
||||
string sessionCookie,
|
||||
IEnumerable<string> group,
|
||||
Permissions debugLevel = Permissions.None)
|
||||
{
|
||||
Mail = p_oMail;
|
||||
Pwd = p_Pwd;
|
||||
SessionCookie = p_oSessionCookie;
|
||||
Mail = mail;
|
||||
Pwd = password;
|
||||
SessionCookie = sessionCookie;
|
||||
DebugLevel = debugLevel;
|
||||
Group = p_strGroup != null
|
||||
? new HashSet<string>(p_strGroup).ToList()
|
||||
Group = group != null
|
||||
? new HashSet<string>(group).ToList()
|
||||
: throw new ArgumentException("Can not instantiate account object. Reference to group list must not be empty.");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
namespace TINK.Model.User.Account
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TINK.Model.User.Account
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface to manage an account store.
|
||||
/// </summary>
|
||||
/// <summary>Interface to manage an account store.</summary>
|
||||
public interface IStore
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads mail address and password from account store.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IAccount Load();
|
||||
Task<IAccount> Load();
|
||||
|
||||
/// <summary>
|
||||
/// Writes mail address and password to account store.
|
||||
/// </summary>
|
||||
/// <param name="p_oMailAndPwd"></param>
|
||||
void Save(IAccount p_oMailAndPwd);
|
||||
/// <param name="mailAndPwd"></param>
|
||||
Task Save(IAccount mailAndPwd);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes mail address and password from account store.
|
||||
/// </summary>
|
||||
/// <returns> Empty account instance if deleting succeeded.</returns>
|
||||
IAccount Delete(IAccount p_oMailAndPwd);
|
||||
IAccount Delete(IAccount mailAndPwd);
|
||||
}
|
||||
}
|
||||
|
|
67
TINKLib/Model/User/Account/Store.cs
Normal file
67
TINKLib/Model/User/Account/Store.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace TINK.Model.User.Account
|
||||
{
|
||||
public class Store : IStore
|
||||
{
|
||||
/// <summary> Holds id of the debug level key. </summary>
|
||||
private const string KEY_DEBUGLEVEL = "DebugLevel";
|
||||
|
||||
/// <summary> Holds the id of the session. </summary>
|
||||
private const string KEY_SESSIONCOOKIE = "SessionCookie";
|
||||
|
||||
/// <summary> Holds id of the mail address key. </summary>
|
||||
private const string KEY_MAILADDRESS = "MailAddress";
|
||||
|
||||
public IAccount Delete(IAccount account)
|
||||
{
|
||||
SecureStorage.RemoveAll();
|
||||
return new EmptyAccount();
|
||||
}
|
||||
|
||||
public async Task<IAccount> Load()
|
||||
{
|
||||
|
||||
var mail = string.Empty;
|
||||
var sessionCookie = string.Empty;
|
||||
var debugLevel = Permissions.None;
|
||||
|
||||
try
|
||||
{
|
||||
mail = await SecureStorage.GetAsync(KEY_MAILADDRESS);
|
||||
sessionCookie = await SecureStorage.GetAsync(KEY_SESSIONCOOKIE);
|
||||
Enum.TryParse(await SecureStorage.GetAsync(KEY_DEBUGLEVEL), out debugLevel);
|
||||
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<Store>().Error("Loading account from store failed. {Exception}", exception);
|
||||
}
|
||||
|
||||
return new Account(
|
||||
mail,
|
||||
string.Empty,
|
||||
sessionCookie,
|
||||
new List<string>(),
|
||||
debugLevel);
|
||||
}
|
||||
|
||||
public async Task Save(IAccount mailAndPwd)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SecureStorage.SetAsync(KEY_MAILADDRESS, mailAndPwd.Mail);
|
||||
await SecureStorage.SetAsync(KEY_SESSIONCOOKIE, mailAndPwd.SessionCookie);
|
||||
await SecureStorage.SetAsync(KEY_DEBUGLEVEL, mailAndPwd.DebugLevel.ToString());
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.ForContext<Store>().Error("Saving account from store failed. {Exception}", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using TINK.Model.User.Account;
|
||||
|
||||
namespace TINK.Model.User
|
||||
|
@ -29,14 +30,14 @@ namespace TINK.Model.User
|
|||
/// </summary>
|
||||
/// <param name="p_oAccountStore"> Object to use for loading and saving user data.</param>
|
||||
public User(
|
||||
IStore p_oAccountStore,
|
||||
IAccount p_oAccount,
|
||||
string p_strDeviceId)
|
||||
IStore accountStore,
|
||||
IAccount account,
|
||||
string deviceId)
|
||||
{
|
||||
m_oStore = p_oAccountStore
|
||||
m_oStore = accountStore
|
||||
?? throw new ArgumentException("Can not instantiate user- object. No store functionality available.");
|
||||
DeviceId = p_strDeviceId;
|
||||
m_oAccount = new AccountMutable(p_oAccount);
|
||||
DeviceId = deviceId;
|
||||
m_oAccount = new AccountMutable(account);
|
||||
}
|
||||
|
||||
/// <summary> Is fired wheneverlogin state changes. </summary>
|
||||
|
@ -109,13 +110,13 @@ namespace TINK.Model.User
|
|||
/// <param name="p_oAccount">Account to use for login.</param>
|
||||
/// <param name="p_str_DeviceId">Holds the Id to identify the device.</param>
|
||||
/// <param name="isConnected">True if connector has access to copri server, false if cached values are used.</param>
|
||||
public void Login(IAccount account)
|
||||
public async Task Login(IAccount account)
|
||||
{
|
||||
// Update account instance from copri data.
|
||||
m_oAccount.Copy(account);
|
||||
|
||||
// Save data to store.
|
||||
m_oStore.Save(m_oAccount);
|
||||
await m_oStore.Save(m_oAccount);
|
||||
|
||||
// Nothing to do because state did not change.
|
||||
StateChanged?.Invoke(this, new EventArgs());
|
||||
|
|
|
@ -316,7 +316,7 @@ namespace TINK.Model
|
|||
},
|
||||
{
|
||||
new Version(3, 0, 208),
|
||||
AppResources.ChangeLog3_0_208
|
||||
AppResources.ChangeLog3_0_208 // Minor fixes.
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 209),
|
||||
|
@ -340,7 +340,7 @@ namespace TINK.Model
|
|||
},
|
||||
{
|
||||
new Version(3, 0, 218),
|
||||
AppResources.ChangeLog3_0_218
|
||||
AppResources.ChangeLog3_0_208
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 219),
|
||||
|
@ -353,8 +353,61 @@ namespace TINK.Model
|
|||
{
|
||||
new Version(3, 0, 222),
|
||||
AppResources.ChangeLog3_0_222
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 223),
|
||||
AppResources.ChangeLog3_0_208
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 224),
|
||||
AppResources.ChangeLog3_0_224
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 225),
|
||||
AppResources.ChangeLog3_0_208
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 226),
|
||||
AppResources.ChangeLog3_0_226
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 227),
|
||||
AppResources.ChangeLog3_0_227
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 228),
|
||||
AppResources.ChangeLog3_0_208
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 231),
|
||||
AppResources.ChangeLog3_0_231
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 232),
|
||||
AppResources.ChangeLog3_0_232
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 234),
|
||||
AppResources.ChangeLog3_0_234
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 235),
|
||||
AppResources.ChangeLog3_0_235
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 236),
|
||||
AppResources.ChangeLog3_0_236
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 237),
|
||||
AppResources.ChangeLog3_0_237
|
||||
},
|
||||
{
|
||||
new Version(3, 0, 238),
|
||||
AppResources.ChangeLog3_0_231
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/// <summary> Manges the whats new information.</summary>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue