Version 3.0.337

This commit is contained in:
Anja Müller-Meißner 2022-08-30 15:42:25 +02:00
parent fd0e63cf10
commit 573fe77e12
2336 changed files with 33688 additions and 86082 deletions

View file

@ -9,7 +9,7 @@ namespace TINK.Repository
{
public AppContextInfo(string merchantId, string name, Version version)
{
Name = !string.IsNullOrEmpty(name)
Name = !string.IsNullOrEmpty(name)
? name
: throw new ArgumentNullException(nameof(name));

View file

@ -1,16 +1,16 @@

using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Serilog;
using TINK.Model.Device;
using TINK.Model.Logging;
using TINK.Repository.Exception;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Model.Logging;
using TINK.Model.Device;
using System.Collections.Generic;
namespace TINK.Repository
{
@ -23,10 +23,12 @@ namespace TINK.Repository
/// <summary> Initializes a instance of the copri calls https object. </summary>
/// <param name="copriHost">Host to connect to. </param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie">Session cookie if user is logged in, null otherwise.</param>
public CopriCallsHttps(
Uri copriHost,
AppContextInfo appContextInfo,
string uiIsoLangugageName,
string sessionCookie = null)
{
m_oCopriHost = copriHost
@ -37,8 +39,8 @@ namespace TINK.Repository
: throw new System.Exception($"Can not construct {GetType()}- object. User agent must not be null or empty.");
requestBuilder = string.IsNullOrEmpty(sessionCookie)
? new RequestBuilder(appContextInfo.MerchantId) as IRequestBuilder
: new RequestBuilderLoggedIn(appContextInfo.MerchantId, sessionCookie);
? new RequestBuilder(appContextInfo.MerchantId, uiIsoLangugageName) as IRequestBuilder
: new RequestBuilderLoggedIn(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie);
}
/// <summary> Holds the URL for rest calls.</summary>
@ -65,27 +67,21 @@ namespace TINK.Repository
string mailAddress,
string password,
string deviceId)
{
return await DoAuthorizationAsync(
=> await DoAuthorizationAsync(
m_oCopriHost.AbsoluteUri,
requestBuilder.DoAuthorization(mailAddress, password, deviceId),
() => requestBuilder.DoAuthorization(mailAddress, "********", deviceId),
UserAgent);
}
/// <summary> Logs user out. </summary>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
public async Task<AuthorizationoutResponse> DoAuthoutAsync()
{
return await DoAuthoutAsync(m_oCopriHost.AbsoluteUri, requestBuilder.DoAuthout(), UserAgent);
}
=> await DoAuthoutAsync(m_oCopriHost.AbsoluteUri, requestBuilder.DoAuthout(), UserAgent);
/// <summary>Gets bikes available.</summary>
/// <returns>Response holding list of bikes.</returns>
public async Task<BikesAvailableResponse> GetBikesAvailableAsync()
{
return await GetBikesAvailableAsync(m_oCopriHost.AbsoluteUri, requestBuilder.GetBikesAvailable(), UserAgent);
}
=> await GetBikesAvailableAsync(m_oCopriHost.AbsoluteUri, requestBuilder.GetBikesAvailable(), UserAgent);
/// <summary> Gets a list of bikes reserved/ booked by acctive user. </summary>
/// <returns>Response holding list of bikes.</returns>
@ -106,10 +102,7 @@ namespace TINK.Repository
/// <summary> Get list of stations. </summary>
/// <returns>List of files.</returns>
public async Task<StationsAvailableResponse> GetStationsAsync()
{
var stations = await GetStationsAsync(m_oCopriHost.AbsoluteUri, requestBuilder.GetStations(), UserAgent);
return stations;
}
=> await GetStationsAsync(m_oCopriHost.AbsoluteUri, requestBuilder.GetStations(), UserAgent);
/// <summary> Get authentication keys. </summary>
/// <param name="bikeId">Id of the bike to get keys for.</param>
@ -125,12 +118,10 @@ namespace TINK.Repository
public async Task<ReservationBookingResponse> DoReserveAsync(
string bikeId,
Uri operatorUri)
{
return await DoReserveAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoReserve(bikeId),
=> await DoReserveAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoReserve(bikeId),
UserAgent);
}
/// <summary> Gets canel booking request response.</summary>
/// <param name="bikeId">Id of the bike to book.</param>
@ -139,12 +130,10 @@ namespace TINK.Repository
public async Task<ReservationCancelReturnResponse> DoCancelReservationAsync(
string bikeId,
Uri operatorUri)
{
return await DoCancelReservationAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoCancelReservation(bikeId),
=> await DoCancelReservationAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoCancelReservation(bikeId),
UserAgent);
}
/// <summary> Get authentication keys. </summary>
/// <param name="bikeId">Id of the bike to get keys for.</param>
@ -154,8 +143,8 @@ namespace TINK.Repository
string bikeId,
Uri operatorUri)
=> await GetAuthKeysAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.CalculateAuthParameters(bikeId),
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.CalculateAuthParameters(bikeId),
UserAgent);
/// <summary> Notifies COPRI about start of returning sequence. </summary>
@ -185,8 +174,8 @@ namespace TINK.Repository
LocationDto location,
double batteryLevel) =>
await DoUpdateLockingStateAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.UpateLockingState(bikeId, state, location, batteryLevel),
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.UpateLockingState(bikeId, state, location, batteryLevel),
UserAgent);
/// <summary> Gets booking request request. </summary>
@ -196,25 +185,37 @@ namespace TINK.Repository
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Requst on booking request.</returns>
public async Task<ReservationBookingResponse> DoBookAsync(
string bikeId,
Guid guid,
string bikeId,
Guid guid,
double batteryPercentage,
Uri operatorUri)
=> await DoBookAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoBook(bikeId, guid, batteryPercentage),
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoBook(bikeId, guid, batteryPercentage),
UserAgent);
/// <summary> Books a bike and starts opening bike. </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on booking request.</returns>
public async Task<ReservationBookingResponse> BookAndStartOpeningAsync(
public async Task<ReservationBookingResponse> BookAvailableAndStartOpeningAsync(
string bikeId,
Uri operatorUri)
=> await DoBookAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.BookAndStartOpening(bikeId),
requestBuilder.BookAvailableAndStartOpening(bikeId),
UserAgent);
/// <summary> Books a bike and starts opening bike. </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on booking request.</returns>
public async Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(
string bikeId,
Uri operatorUri)
=> await DoBookAsync(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.BookReservedAndStartOpening(bikeId),
UserAgent);
/// <summary> Returns a bike. </summary>
@ -224,13 +225,13 @@ namespace TINK.Repository
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on returning request.</returns>
public async Task<DoReturnResponse> DoReturn(
string bikeId,
string bikeId,
LocationDto location,
ISmartDevice smartDevice,
Uri operatorUri)
=> await DoReturn(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoReturn(bikeId, location, smartDevice),
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoReturn(bikeId, location, smartDevice),
UserAgent);
/// <summary> Returns a bike and starts closing. </summary>
@ -249,18 +250,20 @@ namespace TINK.Repository
/// <summary> Submits feedback to copri server. </summary>
/// <param name="bikeId">Id of the bike to which the feedback is related to.</param>
/// <param name="currentChargeBars">Null if bike has no engine or charge is unknown. Otherwise the charge filling level of the drive battery.</param>
/// <param name="isBikeBroken">True if bike is broken.</param>
/// <param name="message">General purpose message or error description.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on submitting feedback request.</returns>
public async Task<SubmitFeedbackResponse> DoSubmitFeedback(
string bikeId,
int? currentChargeBars,
string message,
bool isBikeBroken,
Uri operatorUri) =>
Uri operatorUri) =>
await DoSubmitFeedback(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoSubmitFeedback(bikeId, message, isBikeBroken),
requestBuilder.DoSubmitFeedback(bikeId, currentChargeBars, message, isBikeBroken),
UserAgent);
/// <summary> Submits mini survey to copri server. </summary>
@ -384,7 +387,7 @@ namespace TINK.Repository
// Extract bikes from response.
return CopriCallsStatic.DeserializeResponse(
response,
response,
(version) => CopriCallsMonkeyStore.GetEmptyStationsAllResponse(version));
#else
return null;
@ -392,19 +395,19 @@ namespace TINK.Repository
}
/// <summary> Gets a list of bikes from Copri. </summary>
/// <param name="p_strCopriHost">URL of the copri host to connect to.</param>
/// <param name="copriHost">URL of the copri host to connect to.</param>
/// <param name="p_oCommand">Command to get bikes.</param>
/// <returns>Response holding list of bikes.</returns>
public static async Task<BikesAvailableResponse> GetBikesAvailableAsync(
string p_strCopriHost,
string l_oCommand,
string copriHost,
string command,
string userAgent = null)
{
#if !WINDOWS_UWP
string response;
try
{
response = await PostAsync(p_strCopriHost, l_oCommand, userAgent);
response = await PostAsync(copriHost, command, userAgent);
}
catch (System.Exception l_oException)
{
@ -423,7 +426,7 @@ namespace TINK.Repository
// Extract bikes from response.
return CopriCallsStatic.DeserializeResponse(
response,
response,
(version) => CopriCallsMonkeyStore.GetEmptyBikesAvailableResponse(version));
#else
@ -463,7 +466,7 @@ namespace TINK.Repository
// Extract bikes from response.
return CopriCallsStatic.DeserializeResponse(
response,
response,
(version) => CopriCallsMonkeyStore.GetEmptyBikesReservedOccupiedResponse(version));
#else
return null;
@ -475,33 +478,33 @@ namespace TINK.Repository
/// <param name="command">Command to log user in.</param>
/// <returns>Response on booking request.</returns>
public static async Task<ReservationBookingResponse> GetAuthKeysAsync(
string p_strCopriHost,
string p_oCommand,
string copriHost,
string command,
string userAgent = null)
{
#if !WINDOWS_UWP
string l_oBikesAvaialbeResponse;
string bikesAvaialbeResponse;
try
{
l_oBikesAvaialbeResponse = await PostAsync(p_strCopriHost, p_oCommand, userAgent);
bikesAvaialbeResponse = await PostAsync(copriHost, command, userAgent);
}
catch (System.Exception l_oException)
catch (System.Exception exception)
{
if (l_oException.GetIsConnectFailureException())
if (exception.GetIsConnectFailureException())
{
throw new WebConnectFailureException("Schlosssuche wegen Netzwerkfehler fehlgeschlagen.", l_oException);
throw new WebConnectFailureException("Schlosssuche wegen Netzwerkfehler fehlgeschlagen.", exception);
}
if (l_oException.GetIsForbiddenException())
if (exception.GetIsForbiddenException())
{
throw new WebForbiddenException("Schlosssuche wegen Netzwerkfehler fehlgeschlagen.", l_oException);
throw new WebForbiddenException("Schlosssuche wegen Netzwerkfehler fehlgeschlagen.", exception);
}
throw;
}
// Extract bikes from response.
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(l_oBikesAvaialbeResponse)?.shareejson;
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(bikesAvaialbeResponse)?.shareejson;
#else
return null;
#endif
@ -511,33 +514,33 @@ namespace TINK.Repository
/// <param name="command">Command to log user in.</param>
/// <returns>Response on booking request.</returns>
public static async Task<ReservationBookingResponse> DoReserveAsync(
string p_strCopriHost,
string p_oCommand,
string copriHost,
string command,
string userAgent = null)
{
#if !WINDOWS_UWP
string l_oBikesAvaialbeResponse;
string bikesAvaialbeResponse;
try
{
l_oBikesAvaialbeResponse = await PostAsync(p_strCopriHost, p_oCommand, userAgent);
bikesAvaialbeResponse = await PostAsync(copriHost, command, userAgent);
}
catch (System.Exception l_oException)
catch (System.Exception exception)
{
if (l_oException.GetIsConnectFailureException())
if (exception.GetIsConnectFailureException())
{
throw new WebConnectFailureException("Reservierung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", l_oException);
throw new WebConnectFailureException("Reservierung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", exception);
}
if (l_oException.GetIsForbiddenException())
if (exception.GetIsForbiddenException())
{
throw new WebForbiddenException("Reservierung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", l_oException);
throw new WebForbiddenException("Reservierung des Fahrrads wegen Netzwerkfehler fehlgeschlagen.", exception);
}
throw;
}
// Extract bikes from response.
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(l_oBikesAvaialbeResponse)?.shareejson;
return JsonConvertRethrow.DeserializeObject<ResponseContainer<ReservationBookingResponse>>(bikesAvaialbeResponse)?.shareejson;
#else
return null;
#endif

View file

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TINK.Model;
using TINK.Model.Device;
using TINK.Repository.Request;
using TINK.Repository.Response;
@ -533,6 +532,10 @@ namespace TINK.Repository
""state"": ""reserved"",
""station"" : ""4"",
""description"": ""Cargo Long"",
""bike_type"": {
""category"": ""cargo"",
""wheels"": ""2""
},
""bike_group"" : [ ""TINK"" ],
""start_time"": ""2017-11-28 14:07:13.745568+01"",
""bike"": ""5""
@ -578,7 +581,11 @@ namespace TINK.Repository
""description"": ""Cargo Long"",
""bike_group"" : [ ""TINK"" ],
""start_time"": ""2017-11-28 14:08:32.756368+01"",
""bike"": ""5""
""bike"": ""5"",
""bike_type"": {
""category"": ""cargo"",
""wheels"": ""2""
},
}
},
""authcookie"": ""4da3044c8657a04ba60e2eaa753bc51a"",
@ -917,6 +924,10 @@ namespace TINK.Repository
""description"" : ""Cargo long"",
""bike_group"" : [ ""TINK"" ],
""bike"" : ""5"",
""bike_type"": {
""category"": ""cargo"",
""wheels"": ""2""
},
""state"" : ""available"",
""gps"" : { ""latitude"": ""47.672082"", ""longitude"": ""9.17655283333"" },
""system"" : ""BC"",
@ -1271,17 +1282,20 @@ namespace TINK.Repository
private IRequestBuilder requestBuilder;
public CopriCallsMemory(
string merchantId,
SampleSets? sampleSet = null,
int? index = null,
int? index = null,
string sessionCookie = null)
{
MerchantId = merchantId ?? throw new ArgumentNullException(nameof(merchantId));
ActiveSampleSet = sampleSet ?? DEFAULT_SAMPLE_SET;
ActiveStageIndex = index ?? DEFAULT_STAGE_INDEX;
SessionCookie = sessionCookie;
requestBuilder = string.IsNullOrEmpty(sessionCookie)
? new RequestBuilder(MerchantId) as IRequestBuilder
: new RequestBuilderLoggedIn(MerchantId, sessionCookie);
? new RequestBuilder(MerchantId, null /*UI language */) as IRequestBuilder
: new RequestBuilderLoggedIn(MerchantId, null /*UI language */, sessionCookie);
}
@ -1342,7 +1356,7 @@ namespace TINK.Repository
/// <summary>
/// Get list of stations from file.
/// </summary>
/// <param name="p_strCookie">Auto cookie of user if user is logged in.</param>
/// <param name="p_strCookie">Auto cookie of user if user is logged in.</param>
/// <returns>List of files.</returns>
public async Task<StationsAvailableResponse> GetStationsAsync()
{
@ -1390,7 +1404,7 @@ namespace TINK.Repository
}
/// <summary> Gets the merchant id.</summary>
public string MerchantId => TinkApp.MerchantId;
public string MerchantId { get; private set; }
/// <summary>
/// Gets the active sample set.
@ -1480,7 +1494,7 @@ namespace TINK.Repository
/// <param name="stageIndex">Index of the stage.</param>
/// <returns></returns>
public static BikesAvailableResponse GetBikesAvailable(
string merchantId,
string merchantId,
string sessionCookie = null,
SampleSets sampleSet = DEFAULT_SAMPLE_SET,
long stageIndex = DEFAULT_STAGE_INDEX)
@ -1536,7 +1550,7 @@ namespace TINK.Repository
/// <param name="p_lStageIndex"></param>
/// <returns></returns>
public static StationsAvailableResponse GetStationsAll(
string p_strMerchantId,
string p_strMerchantId,
string p_strCookie = null,
SampleSets p_eSampleSet = DEFAULT_SAMPLE_SET,
long p_lStageIndex = DEFAULT_STAGE_INDEX)
@ -1618,22 +1632,27 @@ namespace TINK.Repository
Uri operatorUri) => null;
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
string bikeId,
string bikeId,
lock_state state,
Uri operatorUri,
LocationDto geolocation,
LocationDto geolocation,
double batteryLevel) => null;
public Task<ReservationBookingResponse> DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
=> null;
public Task<ReservationBookingResponse> BookAndStartOpeningAsync(
public Task<ReservationBookingResponse> BookAvailableAndStartOpeningAsync(
string bikeId,
Uri operatorUri)
=> null;
public Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(
string bikeId,
Uri operatorUri)
=> null;
public Task<DoReturnResponse> DoReturn(
string bikeId,
string bikeId,
LocationDto geolocation,
ISmartDevice smartDevice,
Uri operatorUri)
@ -1645,13 +1664,13 @@ namespace TINK.Repository
Uri operatorUri)
=> throw new NotImplementedException();
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri)
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, int? currentChargeBars, string message, bool isBikeBroken, Uri operatorUri)
=> null;
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
public Task<ResponseBase> DoSubmitMiniSurvey(IDictionary<string, string> answers)
=> null ;
=> null;
/// <summary>
/// Gets a list of bikes reserved/ booked by acctive user from Copri.
@ -1677,7 +1696,7 @@ namespace TINK.Repository
break;
default:
return null;
return null;
}
break;

View file

@ -1,11 +1,11 @@
using MonkeyCache.FileStore;
using System;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MonkeyCache.FileStore;
using TINK.Model.Device;
using TINK.Model.Services.CopriApi;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Model.Services.CopriApi;
using TINK.Model.Device;
using System.Collections.Generic;
namespace TINK.Repository
{
@ -116,17 +116,19 @@ namespace TINK.Repository
/// <summary> Initializes a instance of the copri monkey store object. </summary>
/// <param name="p_strMerchantId">Id of the merchant.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie">Session cookie if user is logged in, null otherwise.</param>
public CopriCallsMonkeyStore(
string merchantId,
string uiIsoLangugageName,
string sessionCookie = null,
TimeSpan? expiresAfter = null)
{
ExpiresAfter = expiresAfter ?? TimeSpan.FromSeconds(1);
requestBuilder = string.IsNullOrEmpty(sessionCookie)
? new RequestBuilder(merchantId) as IRequestBuilder
: new RequestBuilderLoggedIn(merchantId, sessionCookie);
? new RequestBuilder(merchantId, uiIsoLangugageName) as IRequestBuilder
: new RequestBuilderLoggedIn(merchantId, uiIsoLangugageName, sessionCookie);
// Ensure that store holds valid entries.
if (!Barrel.Current.Exists(requestBuilder.GetBikesAvailable()))
@ -165,10 +167,10 @@ namespace TINK.Repository
=> throw new System.Exception("Benachrichtigung von start der Rückgabe im Offlinemodus nicht möglich!");
public Task<ReservationBookingResponse> UpdateLockingStateAsync(
string bikeId,
string bikeId,
lock_state state,
Uri operatorUri,
LocationDto geolocation,
LocationDto geolocation,
double batteryLevel)
=> throw new System.Exception("Aktualisierung des Schlossstatuses im Offlinemodus nicht möglich!");
@ -179,13 +181,22 @@ namespace TINK.Repository
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on booking request.</returns>
public Task<ReservationBookingResponse> BookAndStartOpeningAsync(
public Task<ReservationBookingResponse> BookAvailableAndStartOpeningAsync(
string bikeId,
Uri operatorUri)
=> throw new System.Exception("Buchung mit Start von Schlossöffnen ist im Offlinemodus nicht möglich!");
=> throw new System.Exception("Buchung von verfügbarem Rad mit Start von Schlossöffnen ist im Offlinemodus nicht möglich!");
/// <summary> Books a bike and starts opening bike. </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on booking request.</returns>
public Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(
string bikeId,
Uri operatorUri)
=> throw new System.Exception("Buchung von reserviertem Rad mit Start von Schlossöffnen ist im Offlinemodus nicht möglich!");
public Task<DoReturnResponse> DoReturn(
string bikeId,
string bikeId,
LocationDto geolocation,
ISmartDevice smartDevice,
Uri operatorUri)
@ -202,7 +213,7 @@ namespace TINK.Repository
Uri operatorUri)
=> throw new System.Exception("Rückgabe mit Schloss schließen Befehl im Offlinemodus nicht möglich!");
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri) =>
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, int? currentChargeBars, string message, bool isBikeBroken, Uri operatorUri) =>
throw new System.Exception("Übermittlung von Feedback im Offlinemodus nicht möglich!");
/// <summary> Submits mini survey to copri server. </summary>
@ -289,7 +300,7 @@ namespace TINK.Repository
{
Barrel.Current.Add(
requestBuilder.GetStations(),
JsonConvertRethrow.SerializeObject(stations),
JsonConvertRethrow.SerializeObject(stations),
expiresAfter);
}
}
@ -354,8 +365,8 @@ namespace TINK.Repository
lock (monkeyLock)
{
Barrel.Current.Add(
requestBuilder.GetBikesOccupied(),
JsonConvertRethrow.SerializeObject(bikes),
requestBuilder.GetBikesOccupied(),
JsonConvertRethrow.SerializeObject(bikes),
expiresAfter);
}
}

View file

@ -1,5 +1,5 @@
using Serilog;
using System;
using System;
using Serilog;
using TINK.Model.Connector;
using TINK.Repository.Response;
@ -27,7 +27,7 @@ namespace TINK.Repository
/// <param name="response">Response JSON.</param>
/// <param name="emptyResponseFactory">Factory providing default delegate.</param>
/// <returns>Response object.</returns>
public static T DeserializeResponse<T>(this string response, Func<string, T> emptyResponseFactory) where T: class
public static T DeserializeResponse<T>(this string response, Func<string, T> emptyResponseFactory) where T : class
{
// Get COPRI version from respone.
var bikeInfoBase = JsonConvertRethrow.DeserializeObject<VersionindependentResponse>(response)?.shareejson;

View file

@ -23,12 +23,12 @@
/// <param name="exception">Exception thrown if cookie is not defined.</param>
/// <returns></returns>
public static bool IsAuthcookieNotDefined(
Response.ResponseBase reponse,
string actionText,
Response.ResponseBase reponse,
string actionText,
out AuthcookieNotDefinedException exception)
{
if (reponse == null || reponse.response_state == null)
{
{
// Empty response or response withoud response state is no authcookie not defined exeception.
exception = null;
return false;

View file

@ -1,15 +1,17 @@
namespace TINK.Repository.Exception
using TINK.MultilingualResources;
namespace TINK.Repository.Exception
{
public class InvalidAuthorizationResponseException : InvalidResponseException<Response.ResponseBase>
{
/// <summary>Constructs a authorization exceptions. </summary>
/// <param name="p_strMail">Mail address to create a detailed error message.</param>
public InvalidAuthorizationResponseException(string p_strMail, Response.ResponseBase p_oResponse) :
base(string.Format("Kann Benutzer {0} nicht anmelden. Mailadresse unbekannt oder Passwort ungültig.", p_strMail), p_oResponse)
/// <param name="mail">Mail address to create a detailed error message.</param>
public InvalidAuthorizationResponseException(string mail, Response.ResponseBase response) :
base(string.Format(AppResources.ErrorMessageInvalidAuthorizationResponseException, mail), response)
{
}
/// <summary> Holds error description if user/ password combination is not valid. </summary>
public const string AUTH_FAILURE_STATUS_MESSAGE_UPPERCASE = "FAILURE: CANNOT GENERATE AUTHCOOKIE";
public const string AUTH_FAILURE_STATUS_MESSAGE_UPPERCASE = "FAILURE: CANNOT GENERATE AUTHCOOKIE";
}
}

View file

@ -23,13 +23,13 @@ namespace TINK.Repository.Exception
{
// Check if there are too many bikes requested/ booked.
var match = Regex.Match(
responseState.ToUpper(),
responseState.ToUpper(),
BOOKING_FAILURE_STATUS_MESSAGE_UPPERCASE);
if (match.Groups.Count!= 4
if (match.Groups.Count != 4
|| !int.TryParse(match.Groups[2].ToString(), out int maxBikesCount))
{
exception = null;
return false;
return false;
}
exception = new BookingDeclinedException(maxBikesCount);

View file

@ -3,15 +3,15 @@
public class InvalidResponseException<T> : InvalidResponseException
{
/// <summary> Constructs an invalid response Exception. </summary>
/// <param name="p_strActionWhichFailed">Describes the action which failed.</param>
/// <param name="p_oResponse">Response from copri.</param>
public InvalidResponseException(string p_strActionWhichFailed, T p_oResponse)
/// <param name="actionWhichFailed">Describes the action which failed.</param>
/// <param name="response">Response from copri.</param>
public InvalidResponseException(string actionWhichFailed, T response)
: base(string.Format(
"{0}{1}",
p_strActionWhichFailed,
p_oResponse == null ? string.Format(" Response des Typs {0} ist null.", typeof(T).Name.ToString()) : string.Empty))
"{0}{1}",
actionWhichFailed,
response == null ? string.Format(" Response of type {0} is null.", typeof(T).Name.ToString()) : string.Empty))
{
Response = p_oResponse;
Response = response;
}
public T Response { get; private set; }
@ -27,8 +27,8 @@
{ }
/// <summary> Constructs a invalid response execption.</summary>
/// <param name="p_strMessage">Exception.</param>
public InvalidResponseException(string p_strMessage) : base(p_strMessage)
/// <param name="message">Exception.</param>
public InvalidResponseException(string message) : base(message)
{ }
}
}

View file

@ -3,6 +3,6 @@
public class UnsupportedCopriVersionDetectedException : System.Exception
{
public UnsupportedCopriVersionDetectedException() : base("Unsupported app version detected.")
{}
{ }
}
}

View file

@ -10,12 +10,12 @@ namespace TINK.Repository.Exception
public static string GetHintToPossibleExceptionsReasons
=> AppResources.ExceptionTextWebConnectFailureException;
/// <summary>
/// <summary>
/// Constructs a communication exeption object.
/// </summary>
/// <param name="p_strMessage"></param>
/// <param name="p_oException"></param>
public WebConnectFailureException(string p_strMessage, System.Exception p_oException) : base(p_strMessage, p_oException)
/// <param name="message"></param>
/// <param name="exception"></param>
public WebConnectFailureException(string message, System.Exception exception) : base(message, exception)
{
}
}

View file

@ -20,7 +20,7 @@ namespace TINK.Repository.Exception
return webException.Status == WebExceptionStatus.ConnectFailure // Happens if WLAN and mobile data is off/ Router denies internet access/ ...
|| webException.Status == WebExceptionStatus.NameResolutionFailure // Happens sometimes when not WLAN and no mobil connection are available (bad connection in lift).
|| webException.Status == WebExceptionStatus.ReceiveFailure; // Happened when modile was connected to WLAN
|| webException.Status == WebExceptionStatus.ReceiveFailure; // Happened when mobile was connected to WLAN
}
/// <summary> Gets if a exception is caused by clicking too fast.</summary>

View file

@ -29,7 +29,7 @@ namespace TINK.Repository
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on reserving request.</returns>
Task<ReservationBookingResponse> DoReserveAsync(
string bikeId,
string bikeId,
Uri operatorUri);
/// <summary> Cancels reservation of bik. </summary>
@ -37,7 +37,7 @@ namespace TINK.Repository
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on cancel reservation request.</returns>
Task<ReservationCancelReturnResponse> DoCancelReservationAsync(
string bikeId,
string bikeId,
Uri operatorUri);
/// <summary> Get authentication keys. </summary>
@ -45,7 +45,7 @@ namespace TINK.Repository
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response holding authentication keys.</returns>
Task<ReservationBookingResponse> CalculateAuthKeysAsync(
string bikeId,
string bikeId,
Uri operatorUri);
/// <summary> Notifies COPRI about start of returning sequence. </summary>
@ -78,7 +78,7 @@ namespace TINK.Repository
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on booking request.</returns>
Task<ReservationBookingResponse> DoBookAsync(
string bikeId,
string bikeId,
Guid guid,
double batteryPercentage,
Uri operatorUri);
@ -87,7 +87,15 @@ namespace TINK.Repository
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on booking request.</returns>
Task<ReservationBookingResponse> BookAndStartOpeningAsync(
Task<ReservationBookingResponse> BookAvailableAndStartOpeningAsync(
string bikeId,
Uri operatorUri);
/// <summary> Books a bike and starts opening bike. </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on booking request.</returns>
Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(
string bikeId,
Uri operatorUri);
@ -98,7 +106,7 @@ namespace TINK.Repository
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on returning request.</returns>
Task<DoReturnResponse> DoReturn(
string bikeId,
string bikeId,
LocationDto location,
ISmartDevice smartDevice,
Uri operatorUri);
@ -117,10 +125,12 @@ namespace TINK.Repository
/// Submits feedback to copri server.
/// </summary>
/// <param name="bikeId">Id of the bike to submit feedback for.</param>
/// <param name="currentChargeBars">Null if bike has no engine or charge is unknown. Otherwise the charge filling level of the drive battery.</param>
/// <param name="isBikeBroken">True if bike is broken.</param>
/// <param name="message">General purpose message or error description.</param>
Task<SubmitFeedbackResponse> DoSubmitFeedback(
string bikeId,
int? currentChargeBars,
string message,
bool isBikeBroken,
Uri operatorUri);

View file

@ -67,7 +67,7 @@ namespace TINK.Repository.Request
/// <param name="state">New locking state.</param>
/// <returns>Request to update locking state.</returns>
string UpateLockingState(
string bikeId,
string bikeId,
lock_state state,
LocationDto location = null,
double batteryPercentage = double.NaN);
@ -82,7 +82,12 @@ namespace TINK.Repository.Request
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Request to booking bike.</returns>
string BookAndStartOpening(string bikeId);
string BookAvailableAndStartOpening(string bikeId);
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Request to booking bike.</returns>
string BookReservedAndStartOpening(string bikeId);
/// <summary> Gets request for returning the bike. </summary>
/// <param name="bikeId">Id of the bike to return.</param>
@ -100,9 +105,14 @@ namespace TINK.Repository.Request
/// Gets request for submiting feedback to copri server.
/// </summary>
/// <param name="bikeId">Id of the bike to which the feedback is related to.</param>
/// <param name="currentChargeBars">Null if bike has no engine or charge is unknown. Otherwise the charge filling level of the drive battery.</param>
/// <param name="message">General purpose message or error description.</param>
/// <param name="isBikeBroken">True if bike is broken.</param>
string DoSubmitFeedback(string bikeId, string message = null, bool isBikeBroken = false);
string DoSubmitFeedback(
string bikeId,
int? currentChargeBars,
string message = null,
bool isBikeBroken = false);
/// <summary>
/// Gets request for submiting mini survey to copri server.

View file

@ -0,0 +1,28 @@

namespace TINK.Repository.Request
{
public static class QueryBuilderHelper
{
/// <summary>
/// Gets the htlm query string element for session id.
/// </summary>
/// <returns>Query string.</returns>
public static string GetSessionIdQueryElement(
string op,
string merchantId,
string sessionCookie = null)
=> !string.IsNullOrEmpty(merchantId) || !string.IsNullOrEmpty(sessionCookie)
? $"{op}sessionid={(!string.IsNullOrEmpty(sessionCookie) ? sessionCookie : string.Empty)}{(!string.IsNullOrEmpty(merchantId) ? merchantId : string.Empty)}"
: string.Empty;
/// <summary>
/// Gets the htlm query string element for the language.
/// </summary>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <returns>Query string.</returns>
public static string GetLanguageQueryElement(string op, string uiIsoLangugageName)
=> !string.IsNullOrEmpty(uiIsoLangugageName)
? $"{op}lang={uiIsoLangugageName}"
: string.Empty;
}
}

View file

@ -11,20 +11,32 @@ namespace TINK.Repository.Request
{
/// <summary> Constructs a object for building requests. </summary>
/// <param name="merchantId"></param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
public RequestBuilder(
string merchantId)
string merchantId,
string uiIsoLangugageName)
{
MerchantId = !string.IsNullOrEmpty(merchantId)
? merchantId
: throw new ArgumentException("Merchant id must not be null.", nameof(merchantId));
UiIsoLanguageNameParameter = RequestBuilderHelper.GetLanguageParameter(uiIsoLangugageName);
AuthCookieParameter = $"&authcookie={MerchantId}";
}
/// <summary> Holds the id denoting the merchant (TINK app). </summary>
/// <summary> Parameter specifying current ui language. </summary>
public string MerchantId { get; }
/// <summary> Holds the session cookie if a user is logged in. </summary>
public string SessionCookie => string.Empty;
/// <summary> Holds the current ui two letter ISO language name. </summary>
private string UiIsoLanguageNameParameter { get; }
/// <summary> Auth cookie parameter. </summary>
private string AuthCookieParameter { get; }
/// <summary> Gets request to log user in. </summary>
/// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="password">Password to log in.</param>
@ -34,67 +46,53 @@ namespace TINK.Repository.Request
string mailAddress,
string password,
string deviceId)
{
return string.Format(
"request=authorization&merchant_id={0}&user_id={1}&user_pw={2}&hw_id={3}",
MerchantId,
WebUtility.UrlEncode(mailAddress),
WebUtility.UrlEncode(password),
deviceId);
}
=> "request=authorization" +
$"&merchant_id={MerchantId}" +
$"&user_id={WebUtility.UrlEncode(mailAddress)}" +
$"&user_pw={WebUtility.UrlEncode(password)}" +
$"&hw_id={deviceId}" +
UiIsoLanguageNameParameter;
/// <summary> Logs user out. </summary>
public string DoAuthout()
{
throw new CallNotRequiredException();
}
=> throw new CallNotRequiredException();
/// <summary>Gets bikes available.</summary>
/// <returns>Request to query list of bikes available.</returns>
public string GetBikesAvailable()
{
return GetBikesAvailable(MerchantId);
}
/// <summary>Gets bikes available.</summary>
/// <returns>Request to query list of bikes available.</returns>
public static string GetBikesAvailable(string merchantId, string sessionCookie = null)
{
return $"request=bikes_available&system=all&authcookie={sessionCookie ?? string.Empty}{merchantId}";
}
=> "request=bikes_available&system=all" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Get list of stations from file. </summary>
/// <returns>Request to query list of station.</returns>
public string GetStations()
{
return GetStations(MerchantId);
}
/// <summary> Get list of stations from file. </summary>
/// <returns>Request to query list of station.</returns>
public static string GetStations(string merchantId, string sessionCookie = null)
{
return $"request=stations_available&authcookie={sessionCookie ?? string.Empty}{merchantId}";
}
=> "request=stations_available" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <returns>Request to query list of bikes occupied.</returns>
public string GetBikesOccupied() => throw new NotSupportedException();
public string GetBikesOccupied()
=> throw new NotSupportedException();
/// <summary> Gets booking request response. </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Response on booking request.</returns>
public string DoReserve(string bikeId) => throw new NotSupportedException();
public string DoReserve(string bikeId)
=> throw new NotSupportedException();
/// <summary> Gets cancel booking request response. </summary>
/// <param name="p_iBikeId">Id of the bike to book.</param>
/// <returns>Response on cancel booking request.</returns>
public string DoCancelReservation(string p_iBikeId) => throw new NotSupportedException();
public string DoCancelReservation(string p_iBikeId)
=> throw new NotSupportedException();
/// <summary> Request to calculate authentication keys. </summary>
/// <param name="bikeId">Id of the bike to get keys for.</param>
/// <returns>Response on request.</returns>
public string CalculateAuthParameters(string bikeId) => throw new NotSupportedException();
public string CalculateAuthParameters(string bikeId)
=> throw new NotSupportedException();
/// <summary> Gets the request for notifying about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
@ -103,33 +101,41 @@ namespace TINK.Repository.Request
public string StartReturningBike(string bikeId)
=> throw new NotSupportedException();
public string UpateLockingState(string bikeId, lock_state state, LocationDto geolocation, double batteryPercentage)
public string UpateLockingState(string bikeId, lock_state state, LocationDto geolocation, double batteryPercentage)
=> throw new NotSupportedException();
public string DoBook(string bikeId, Guid guid, double batteryPercentage) => throw new NotSupportedException();
public string DoBook(string bikeId, Guid guid, double batteryPercentage)
=> throw new NotSupportedException();
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Request to booking bike.</returns>
public string BookAndStartOpening(string bikeId) => throw new NotSupportedException();
public string BookAvailableAndStartOpening(string bikeId)
=> throw new NotSupportedException();
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice) => throw new NotSupportedException();
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Request to booking bike.</returns>
public string BookReservedAndStartOpening(string bikeId)
=> throw new NotSupportedException();
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice)
=> throw new NotSupportedException();
/// <summary> Returns a bike and starts closing. </summary>
/// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
/// <returns>Response to send to corpi.</returns>
public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice) => throw new NotSupportedException();
public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice)
=> throw new NotSupportedException();
/// <summary> Gets submit feedback request. </summary>
/// <param name="bikeId">Id of the bike to which the feedback is related to.</param>
/// <param name="message">General purpose message or error description.</param>
/// <param name="isBikeBroken">True if bike is broken.</param>
/// <returns>Submit feedback request.</returns>
public string DoSubmitFeedback(
string bikeId,
string message = null,
bool isBikeBroken = false) => throw new NotSupportedException();
public string DoSubmitFeedback(string bikeId, int? currentChargeBars, string message = null, bool isBikeBroken = false)
=> throw new NotSupportedException();
/// <summary>
/// Gets request for submiting mini survey to copri server.

View file

@ -0,0 +1,16 @@

namespace TINK.Repository.Request
{
public static class RequestBuilderHelper
{
/// <summary>
/// Gets the REST language parameter.
/// </summary>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <returns></returns>
public static string GetLanguageParameter(string uiIsoLangugageName)
=> !string.IsNullOrEmpty(uiIsoLangugageName)
? $"&lang={uiIsoLangugageName}"
: string.Empty;
}
}

View file

@ -5,6 +5,7 @@ using System.Linq;
using System.Net;
using TINK.Model.Device;
using TINK.Repository.Exception;
using TINK.Services.Logging;
namespace TINK.Repository.Request
{
@ -13,8 +14,10 @@ namespace TINK.Repository.Request
{
/// <summary> Constructs a object for building requests. </summary>
/// <param name="merchantId"></param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
public RequestBuilderLoggedIn(
string merchantId,
string uiIsoLangugageName,
string sessionCookie)
{
MerchantId = !string.IsNullOrEmpty(merchantId)
@ -24,6 +27,10 @@ namespace TINK.Repository.Request
SessionCookie = !string.IsNullOrEmpty(sessionCookie)
? sessionCookie
: throw new ArgumentException("Session cookie must not be null.", nameof(sessionCookie));
UiIsoLanguageNameParameter = RequestBuilderHelper.GetLanguageParameter(uiIsoLangugageName);
AuthCookieParameter = $"&authcookie={SessionCookie}{MerchantId}";
}
/// <summary> Holds the id denoting the merchant (TINK app). </summary>
@ -32,6 +39,12 @@ namespace TINK.Repository.Request
/// <summary> Holds the session cookie if a user is logged in. </summary>
public string SessionCookie { get; }
/// <summary> Holds the current ui two letter ISO language name. </summary>
public string UiIsoLanguageNameParameter { get; }
/// <summary> Auth cookie parameter. </summary>
private string AuthCookieParameter { get; }
/// <summary> Gets request to log user in. </summary>
/// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="password">Password to log in.</param>
@ -41,66 +54,76 @@ namespace TINK.Repository.Request
string mailAddress,
string password,
string deviceId)
{
throw new CallNotRequiredException();
}
=> throw new CallNotRequiredException();
/// <summary> Logs user out. </summary>
public string DoAuthout()
{
return $"request=authout&authcookie={SessionCookie}{MerchantId}";
}
=> "request=authout" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary>Gets bikes available.</summary>
/// <returns>Request to query list of bikes available.</returns>
public string GetBikesAvailable()
{
return RequestBuilder.GetBikesAvailable(MerchantId, SessionCookie);
}
=> "request=bikes_available&system=all" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <returns>Request to query list of bikes occupied.</returns>
public string GetBikesOccupied()
{
return !string.IsNullOrEmpty(SessionCookie)
? $"request=user_bikes_occupied&system=all&genkey=1&authcookie={SessionCookie}{MerchantId}"
: "request=bikes_available";
}
=> "request=user_bikes_occupied&system=all&genkey=1" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Get list of stations from file. </summary>
/// <returns>Request to query list of station.</returns>
public string GetStations()
{
return $"request=stations_available&authcookie={SessionCookie ?? string.Empty}{MerchantId}";
}
=> "request=stations_available" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Gets reservation request (synonym: reservation == request == reservieren). </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bikeId">Id of the bike to reserve.</param>
/// <returns>Requst to reserve bike.</returns>
public string DoReserve(string bikeId)
=> $"request=booking_request&bike={bikeId}&authcookie={SessionCookie}{MerchantId}";
=> "request=booking_request" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Gets request to cancel reservation. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bikeId">Id of the bike to cancel reservation for.</param>
/// <returns>Requst on cancel booking request.</returns>
public string DoCancelReservation(string p_iBikeId)
=> $"request=booking_cancel&bike={p_iBikeId}&authcookie={SessionCookie}{MerchantId}";
public string DoCancelReservation(string bikeId)
=> "request=booking_cancel" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Request to get keys. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bikeId">Id of the bike to get keys for.</param>
/// <returns>Request to get keys.</returns>
public string CalculateAuthParameters(string bikeId)
=> $"request=booking_update&bike={bikeId}&authcookie={SessionCookie}{MerchantId}&genkey=1";
=> "request=booking_update" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
"&genkey=1" +
UiIsoLanguageNameParameter;
/// <summary> Gets the request for notifying about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bikeId">Id of the bike to return.</param>
/// <returns>Request to notify about start of returning sequence.</returns>
public string StartReturningBike(string bikeId)
=> $"request=booking_update&bike={bikeId}&lock_state=locking&authcookie={SessionCookie}{MerchantId}";
=> "request=booking_update" +
GetBikeIdParameter(bikeId) +
GetLockStateParameter(lock_state.locking) +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Gets the request for updating lock state for a booked bike. </summary>
/// <remarks> Operator specific call.</remarks>
@ -108,11 +131,18 @@ namespace TINK.Repository.Request
/// <param name="state">New locking state.</param>
/// <returns>Request to update locking state.</returns>
public string UpateLockingState(
string bikeId,
lock_state state,
LocationDto geolocation,
string bikeId,
lock_state state,
LocationDto geolocation,
double batteryPercentage)
=> $"request=booking_update&bike={bikeId}{GetLocationParameters(geolocation)}&lock_state={state}{GetBatteryPercentageParameters(batteryPercentage)}&authcookie={SessionCookie}{MerchantId}";
=> "request=booking_update" +
GetBikeIdParameter(bikeId) +
GetLocationParameters(geolocation) +
GetLockStateParameter(state) +
GetBatteryPercentageParameters(batteryPercentage) +
AuthCookieParameter +
UiIsoLanguageNameParameter;
/// <summary> Gets booking request request (synonym: booking == renting == mieten). </summary>
/// <remarks> Operator specific call.</remarks>
@ -121,13 +151,36 @@ namespace TINK.Repository.Request
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
/// <returns>Request to booking bike.</returns>
public string DoBook(string bikeId, Guid guid, double batteryPercentage)
=> $"request=booking_update&bike={bikeId}&authcookie={SessionCookie}{MerchantId}&Ilockit_GUID={guid}&state=occupied&lock_state=unlocked{GetBatteryPercentageParameters(batteryPercentage)}";
=> "request=booking_update" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
$"&Ilockit_GUID={guid}" +
"&state=occupied" +
GetLockStateParameter(lock_state.unlocked) +
GetBatteryPercentageParameters(batteryPercentage) +
UiIsoLanguageNameParameter;
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Request to booking bike.</returns>
public string BookAndStartOpening(string bikeId)
=> $"request=booking_request&bike={bikeId}&authcookie={SessionCookie}{MerchantId}&state=occupied&lock_state={lock_state.unlocking}";
public string BookAvailableAndStartOpening(string bikeId)
=> "request=booking_request" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
"&state=occupied" +
GetLockStateParameter(lock_state.unlocking) +
UiIsoLanguageNameParameter;
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
/// <param name="bikeId">Id of the bike to book.</param>
/// <returns>Request to booking bike.</returns>
public string BookReservedAndStartOpening(string bikeId)
=> "request=booking_update" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
"&state=occupied" +
GetLockStateParameter(lock_state.unlocking) +
UiIsoLanguageNameParameter;
/// <summary> Gets request for returning the bike. </summary>
/// <remarks> Operator specific call.</remarks>
@ -135,25 +188,29 @@ namespace TINK.Repository.Request
/// <param name="geolocation">Geolocation of lock when returning bike.</param>
/// <returns>Requst on returning request.</returns>
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice)
=> $"request=booking_update" +
$"&bike={bikeId}" +
$"&authcookie={SessionCookie}{MerchantId}" +
$"&state=available" +
$"{GetLocationParameters(geolocation)}" +
$"&lock_state=locked" +
$"{GetSmartDeviceParameters(smartDevice)}";
=> "request=booking_update" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
"&state=available" +
GetLocationParameters(geolocation) +
GetLockStateParameter(lock_state.locked) +
GetSmartDeviceParameters(smartDevice) +
GetLog() +
UiIsoLanguageNameParameter;
/// <summary> Returns a bike and starts closing. </summary>
/// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
/// <returns>Response to send to corpi.</returns>
public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice)
=> $"request=booking_update" +
$"&bike={bikeId}" +
$"&authcookie={SessionCookie}{MerchantId}" +
$"&state=available" +
$"&lock_state={lock_state.locking}" +
$"{GetSmartDeviceParameters(smartDevice)}";
=> "request=booking_update" +
GetBikeIdParameter(bikeId) +
AuthCookieParameter +
"&state=available" +
GetLockStateParameter(lock_state.locking) +
GetSmartDeviceParameters(smartDevice) +
UiIsoLanguageNameParameter;
/// <summary> Gets submit feedback request. </summary>
/// <param name="bikeId">Id of the bike to return.</param>
@ -162,60 +219,28 @@ namespace TINK.Repository.Request
/// <returns>Submit feedback request.</returns>
public string DoSubmitFeedback(
string bikeId,
int? currentChargeBars = null,
string message = null,
bool isBikeBroken = false)
{
if (string.IsNullOrEmpty(message) && !isBikeBroken)
{
// User just acknoledged biked returned message.
return $"request=user_feedback&bike={bikeId}&authcookie={SessionCookie}{MerchantId}";
}
string GetIsBikeBroken()
=> isBikeBroken ? "&bike_broken=1" : string.Empty;
if (isBikeBroken == false)
{
// Bike is ok and user entered a feedback message.
return $"request=user_feedback&bike={bikeId}&message={WebUtility.UrlEncode(message)}&authcookie={SessionCookie}{MerchantId}";
}
string GetMessage()
=> !string.IsNullOrEmpty(message) ? $"&message={WebUtility.UrlEncode(message)}" : string.Empty;
string GetCurrentChargeBars()
=> currentChargeBars != null ? $"&charge_current_bars={currentChargeBars.Value}" : string.Empty;
if (string.IsNullOrEmpty(message))
{
// User just marked bike as broken without comment.
return $"request=user_feedback&bike={bikeId}&bike_broken=1&authcookie={SessionCookie}{MerchantId}";
}
// Bike is marked as broken and user added a comment.
return $"request=user_feedback&bike={bikeId}&bike_broken=1&message={WebUtility.UrlEncode(message)}&authcookie={SessionCookie}{MerchantId}";
return "request=user_feedback" +
GetBikeIdParameter(bikeId) +
GetCurrentChargeBars() +
GetIsBikeBroken() +
GetMessage() +
AuthCookieParameter +
UiIsoLanguageNameParameter;
}
private string GetBatteryPercentageParameters(double batteryPercentage) => !double.IsNaN(batteryPercentage)
? $"&voltage={batteryPercentage.ToString(CultureInfo.InvariantCulture)}"
: string.Empty;
/// <summary> Gets the geolocation parameter. </summary>
/// <param name="geolocation">Geolocation or null.</param>
private string GetLocationParameters(LocationDto geolocation)
{
if (geolocation == null)
return string.Empty;
if (geolocation.Accuracy == null)
return $"&gps={geolocation.Latitude.ToString(CultureInfo.InvariantCulture)},{ geolocation.Longitude.ToString(CultureInfo.InvariantCulture)}&gps_age={geolocation.Age.TotalSeconds}";
return $"&gps={geolocation.Latitude.ToString(CultureInfo.InvariantCulture)},{geolocation.Longitude.ToString(CultureInfo.InvariantCulture)}&gps_accuracy={geolocation.Accuracy.Value.ToString(CultureInfo.InvariantCulture)}&gps_age={geolocation.Age.TotalSeconds}";
}
/// <summary> Gets the geolocation parameter. </summary>
/// <param name="geolocation">Geolocation or null.</param>
private string GetSmartDeviceParameters(ISmartDevice smartDevice)
=> smartDevice != null
? $"{(!string.IsNullOrEmpty(smartDevice.Manufacturer) ? $"&user_device_manufaturer={smartDevice.Manufacturer})" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Model) ? $"&user_device_model={smartDevice.Model}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.PlatformText) ? $"&user_device_platform={smartDevice.PlatformText}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.VersionText) ? $"&user_device_version={smartDevice.VersionText}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Identifier) ? $"&user_device_id={smartDevice.Identifier}" : string.Empty)}"
: string.Empty;
/// <summary>
/// Gets request for submiting mini survey to copri server.
/// </summary>
@ -224,12 +249,63 @@ namespace TINK.Repository.Request
{
// Remove entires which invalid keys or values.
var validAnsers = answers?.Where(x => !string.IsNullOrEmpty(x.Key?.Trim()) && !string.IsNullOrEmpty(x.Value?.Trim()));
// Create quersy
return validAnsers != null && validAnsers.Count() > 0
? $"request=user_minianswer&{string.Join("&", validAnsers.Select(x => $"{x.Key}={WebUtility.UrlEncode(x.Value)}"))}&authcookie={SessionCookie}{MerchantId}"
: $"request=user_minianswer&authcookie={SessionCookie}{MerchantId}";
// Create quersy
if (validAnsers == null || validAnsers.Count() <= 0)
return "request=user_minianswer" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
return "request=user_minianswer" +
$"&{string.Join("&", validAnsers.Select(x => $"{x.Key}={WebUtility.UrlEncode(x.Value)}"))}" +
AuthCookieParameter +
UiIsoLanguageNameParameter;
}
private static string GetBikeIdParameter(string bikeId)
=> $"&bike={bikeId}";
private static string GetLockStateParameter(lock_state lockState)
=> $"&lock_state={lockState}";
private static string GetBatteryPercentageParameters(double batteryPercentage) => !double.IsNaN(batteryPercentage)
? $"&voltage={batteryPercentage.ToString(CultureInfo.InvariantCulture)}"
: string.Empty;
/// <summary> Gets the geolocation parameter. </summary>
/// <param name="geolocation">Geolocation or null.</param>
private static string GetLocationParameters(LocationDto geolocation)
{
if (geolocation == null)
return string.Empty;
if (geolocation.Accuracy == null)
return $"&gps={geolocation.Latitude.ToString(CultureInfo.InvariantCulture)},{geolocation.Longitude.ToString(CultureInfo.InvariantCulture)}&gps_age={geolocation.Age.TotalSeconds}";
return $"&gps={geolocation.Latitude.ToString(CultureInfo.InvariantCulture)},{geolocation.Longitude.ToString(CultureInfo.InvariantCulture)}&gps_accuracy={geolocation.Accuracy.Value.ToString(CultureInfo.InvariantCulture)}&gps_age={geolocation.Age.TotalSeconds}";
}
/// <summary> Gets the geolocation parameter. </summary>
/// <param name="geolocation">Geolocation or null.</param>
private static string GetSmartDeviceParameters(ISmartDevice smartDevice)
=> smartDevice != null
? $"{(!string.IsNullOrEmpty(smartDevice.Manufacturer) ? $"&user_device_manufaturer={smartDevice.Manufacturer})" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Model) ? $"&user_device_model={smartDevice.Model}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Platform.ToString()) ? $"&user_device_platform={smartDevice.Platform.ToString()}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.VersionText) ? $"&user_device_version={smartDevice.VersionText}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Identifier) ? $"&user_device_id={smartDevice.Identifier}" : string.Empty)}"
: string.Empty;
/// <summary>
/// Gets logging entries from serilog.
/// </summary>
/// <returns></returns>
private static string GetLog()
{
var messages = string.Join("\n", MemoryStackSink.PopAllMessages());
return !string.IsNullOrEmpty(messages)
? "&app_debug=" + WebUtility.UrlEncode(string.Join("\n", messages))
: string.Empty;
}
}
}

View file

@ -5,18 +5,12 @@ namespace TINK.Repository.Response
[DataContract]
public class BikeInfoAvailable : BikeInfoBase
{
/// <summary>
/// Position of the bike.
/// </summary>
/// <summary>Mini survey for bikes which were rented before and for which feedback is pending.</summary>
[DataMember]
public Position gps { get; private set; }
public MiniSurveyResponse user_miniquery { get; private set; }
/// <summary> Information about Co2- saving for bikes which were rented before and for which feedback is pending.</summary>
[DataMember]
/// <summary> Full advertisement name.</summary>
public string Ilockit_ID { get; private set; }
[DataMember]
/// <summary> Full advertisement name.</summary>
public string Ilockit_GUID { get; private set; }
public string co2saving { get; private set; }
}
}

View file

@ -1,4 +1,4 @@
 using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace TINK.Repository.Response
{
@ -14,6 +14,12 @@ namespace TINK.Repository.Response
[DataMember]
public string bike { get; private set; }
/// <summary>
/// Position of the bike.
/// </summary>
[DataMember]
public Position gps { get; private set; }
/// <summary>
/// Id of the station.
/// </summary>
@ -68,6 +74,10 @@ namespace TINK.Repository.Response
[DataMember]
public RentalDescription rental_description { get; private set; }
#endif
[DataMember]
/// <summary> Describes type of the bike.</summary>
public BikeType bike_type { get; private set; }
/// <summary> Loading state of motor battery in % ]0..100[. </summary>
[DataMember]
public string bike_charge { get; private set; }
@ -76,6 +86,14 @@ namespace TINK.Repository.Response
[DataMember]
public string lock_state { get; private set; }
[DataMember]
/// <summary> Full advertisement name.</summary>
public string Ilockit_ID { get; private set; }
[DataMember]
/// <summary> Full advertisement name.</summary>
public string Ilockit_GUID { get; private set; }
/// <summary>
/// Textual description of response.
/// </summary>

View file

@ -3,7 +3,7 @@
namespace TINK.Repository.Response
{
[DataContract]
public class BikeInfoReservedOrBooked : BikeInfoAvailable
public class BikeInfoReservedOrBooked : BikeInfoBase
{
/// <summary>
/// Date from when bike was reserved from/ booked from.
@ -26,7 +26,7 @@ namespace TINK.Repository.Response
[DataMember]
/// <summary> Key for connect to bluetooth lock as admin.</summary>
public string K_a { get; private set;}
public string K_a { get; private set; }
}
}

View file

@ -0,0 +1,85 @@
using System.Runtime.Serialization;
namespace TINK.Repository.Response
{
/// <summary>
/// Holds info about a single bike.
/// </summary>
[DataContract]
public class BikeType
{
/// <summary>
/// Holds the engine.
/// </summary>
[DataContract]
public class Engine
{
/// <summary>
/// Manufacturer: ...
/// </summary>
[DataMember]
public string manufacturer { get; private set; }
}
/// <summary>
/// Holds the engine.
/// </summary>
[DataContract]
public class Battery
{
/// <summary>
/// Holds the current charging level in bars.
/// </summary>
[DataMember]
public string charge_current_bars { get; private set; }
/// <summary>
/// Holds the current charging level of the battery in percent.
/// </summary>
[DataMember]
public string charge_current_percent { get; private set; }
/// <summary>
/// Holds the maximum chargeing level of the battery in bars.
/// </summary>
[DataMember]
public string charge_max_bars { get; private set; }
/// <summary>
/// Holds whether backend is aware of battery charging level.
/// </summary>
[DataMember]
public string backend_accessible { get; private set; }
/// <summary>
/// Holds whether to display battery level or not.
/// </summary>
[DataMember]
public string hidden { get; private set; }
}
/// <summary>
/// Category of the bike. Possible entries: "city", "cargo", ...
/// </summary>
[DataMember]
public string category { get; private set; }
/// <summary>
/// Count of wheels. There are trikes (3 wheels) and two wheeled bikes.
/// </summary>
[DataMember]
public string wheels { get; private set; }
/// <summary>
/// Holds engine information. .
/// </summary>
[DataMember]
public Engine engine { get; private set; }
/// <summary>
/// Holds battery information .
/// </summary>
[DataMember]
public Battery battery { get; private set; }
}
}

View file

@ -13,6 +13,6 @@ namespace TINK.Repository.Response
/// Dictionary of bikes.
/// </summary>
[DataMember]
public Dictionary<string, BikeInfoAvailable> bikes { get; private set; }
public Dictionary<string, BikeInfoAvailable> bikes { get; private set; }
}
}

View file

@ -10,6 +10,5 @@ namespace TINK.Repository.Response
[DataMember]
public string co2saving { get; private set; }
}
}

View file

@ -3,32 +3,32 @@ using System.Runtime.Serialization;
namespace TINK.Repository.Response
{
[DataContract]
public class MiniSurveyResponse
{
[DataContract]
public class MiniSurveyResponse
public class Question
{
[DataContract]
public class Question
{
[DataMember]
public string quest_text { get; private set; }
[DataMember]
public string type { get; private set; }
[DataMember]
public Dictionary<string, string> query { get; private set; }
}
[DataMember]
public string quest_text { get; private set; }
[DataMember]
public string title { get; private set; }
public string type { get; private set; }
[DataMember]
public string subtitle { get; private set; }
[DataMember]
public string footer { get; private set; }
[DataMember]
public Dictionary<string, Question> questions { get; private set; }
public Dictionary<string, string> query { get; private set; }
}
[DataMember]
public string title { get; private set; }
[DataMember]
public string subtitle { get; private set; }
[DataMember]
public string footer { get; private set; }
[DataMember]
public Dictionary<string, Question> questions { get; private set; }
}
}

View file

@ -27,13 +27,15 @@ namespace TINK.Repository.Response
public Dictionary<
string /* Key of tariff object for sorting purposes*/,
string[] /* Holds two Elements: first element is the description of the element (example: "Max Gebühr"), second is the value (example: "9.00 € / Tag")*/>
tarif_elements { get; private set; }
tarif_elements
{ get; private set; }
/// <summary> Holds tariff entires to show to user.</summary>
[DataMember]
public Dictionary<
string /* Key of info object for sorting purposes*/,
string[] /* Holds two Elements: first element is the key of the element (example: "Tracking"), second is the value (example: "Ich stimme der Speicherung (Tracking) meiner Fahrstrecke ....")*/>
rental_info { get; private set; }
rental_info
{ get; private set; }
}
}

View file

@ -43,7 +43,7 @@ namespace TINK.Repository.Response
/// <summary> Url of page holding tariff info. </summary>
[DataMember]
public string tariff_info_html { get; private set; }
public string tariff_info_html { get; private set; }
/// <summary> Textual description of response. </summary>
public new string ToString()

View file

@ -1,6 +1,6 @@
using System.Linq;
using TINK.Repository.Exception;
using TINK.MultilingualResources;
using TINK.Repository.Exception;
namespace TINK.Repository.Response
{
@ -60,7 +60,7 @@ namespace TINK.Repository.Response
/// <param name="p_oResponse">Response to check whether it is valid.</param>
/// <returns></returns>
public static AuthorizationoutResponse GetIsResponseOk(this AuthorizationoutResponse p_oResponse)
{
{
if (AuthcookieNotDefinedException.IsAuthcookieNotDefined(p_oResponse, BIKES_LOGOUT_ACTIONTEXT, out AuthcookieNotDefinedException exception))
{
throw exception;
@ -71,7 +71,7 @@ namespace TINK.Repository.Response
if (p_oResponse.authcookie != "1")
{
throw new InvalidResponseException<AuthorizationoutResponse>(
BIKES_LOGOUT_ACTIONTEXT,
BIKES_LOGOUT_ACTIONTEXT,
p_oResponse);
}
@ -93,7 +93,7 @@ namespace TINK.Repository.Response
{
throw exception;
}
// Get bike which has to be booked.
var bikeInfoRequestedOccupied = bookingResponse?.bikes_occupied?.Values?.FirstOrDefault(x => x.bike == bikeId);
if (bikeInfoRequestedOccupied == null)
@ -162,7 +162,7 @@ namespace TINK.Repository.Response
/// <param name="response">Response to verify.</param>
/// <param name="textOfAction">Text describing request which is shown if validation fails.</param>
/// <returns>Verified response.</returns>
public static T GetIsResponseOk<T>(this T response, string textOfAction) where T : ResponseBase
public static T GetIsResponseOk<T>(this T response, string textOfAction) where T : ResponseBase
{
if (response == null || response.response_state == null)
{

View file

@ -4,7 +4,7 @@ namespace TINK.Repository.Response
{
[DataContract]
public class VersionindependentResponse
{
{
private CopriVersion _shareejson;
/// <summary> Root element for versions 4.0 and older. </summary>
@ -13,7 +13,7 @@ namespace TINK.Repository.Response
/// <summary> Root element from 4.1 and later. </summary>
[DataMember]
public CopriVersion shareejson
public CopriVersion shareejson
{
get => _shareejson ?? tinkjson;
private set { _shareejson = value; }