2022-09-20 13:51:55 +02:00
using System ;
2021-08-01 17:24:15 +02:00
using System.Collections.Generic ;
2021-05-13 20:03:07 +02:00
using System.Globalization ;
2021-08-01 17:24:15 +02:00
using System.Linq ;
2021-05-13 20:03:07 +02:00
using System.Net ;
2022-09-20 13:51:55 +02:00
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock ;
2022-12-27 21:08:09 +01:00
using TINK.Model.Connector ;
2021-06-26 20:57:55 +02:00
using TINK.Model.Device ;
using TINK.Repository.Exception ;
2022-08-30 15:42:25 +02:00
using TINK.Services.Logging ;
2021-05-13 20:03:07 +02:00
2021-06-26 20:57:55 +02:00
namespace TINK.Repository.Request
2021-05-13 20:03:07 +02:00
{
2022-09-06 16:08:19 +02:00
/// <summary> Creates requests if a user is logged in.</summary>
public class RequestBuilderLoggedIn : IRequestBuilder
{
/// <summary> Constructs a object for building requests. </summary>
2023-01-18 14:22:51 +01:00
/// <param name="merchantId">Holds the id denoting the merchant.</param>
2022-09-06 16:08:19 +02:00
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
2023-02-22 14:03:35 +01:00
/// <param name="smartDevice">Holds info about smart device.</param>
2022-09-06 16:08:19 +02:00
public RequestBuilderLoggedIn (
string merchantId ,
string uiIsoLangugageName ,
2023-02-22 14:03:35 +01:00
string sessionCookie ,
ISmartDevice smartDevice = null )
2022-09-06 16:08:19 +02:00
{
MerchantId = ! string . IsNullOrEmpty ( merchantId )
? merchantId
: throw new ArgumentException ( "Merchant id must not be null." , nameof ( merchantId ) ) ;
SessionCookie = ! string . IsNullOrEmpty ( sessionCookie )
? sessionCookie
: throw new ArgumentException ( "Session cookie must not be null." , nameof ( sessionCookie ) ) ;
2023-01-18 14:22:51 +01:00
UiIsoLanguageNameParameter = RequestBuilderHelper . GetLanguageParameter ( WebUtility . UrlEncode ( uiIsoLangugageName ) ) ;
2022-09-06 16:08:19 +02:00
2023-01-18 14:22:51 +01:00
AuthCookieParameter = $"&authcookie={WebUtility.UrlEncode(SessionCookie)}{WebUtility.UrlEncode(MerchantId)}" ;
2023-02-22 14:03:35 +01:00
SmartDevice = smartDevice ;
2022-09-06 16:08:19 +02:00
}
2023-01-18 14:22:51 +01:00
/// <summary> Holds the id denoting the merchant. </summary>
2022-09-06 16:08:19 +02:00
public string MerchantId { get ; }
/// <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 ; }
2023-02-22 14:03:35 +01:00
/// <summary>Holds info about smart device.</summary>
private ISmartDevice SmartDevice { get ; }
2022-09-06 16:08:19 +02:00
/// <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>
/// <param name="deviceId">Id specifying user and hardware.</param>
/// <remarks>Response which holds auth cookie <see cref="ResponseBase.authcookie"/></remarks>
public string DoAuthorization (
string mailAddress ,
string password ,
string deviceId )
= > throw new CallNotRequiredException ( ) ;
/// <summary> Logs user out. </summary>
public string DoAuthout ( )
= > "request=authout" +
AuthCookieParameter +
UiIsoLanguageNameParameter ;
/// <summary>Gets bikes available.</summary>
/// <returns>Request to query list of bikes available.</returns>
public string GetBikesAvailable ( )
= > "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 ( )
= > "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 ( )
= > "request=stations_available" +
AuthCookieParameter +
2023-02-22 14:03:35 +01:00
SmartDevice . GetSmartDeviceParameters ( ) +
2022-09-06 16:08:19 +02:00
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" +
GetBikeIdParameter ( bikeId ) +
AuthCookieParameter +
2023-02-22 14:03:35 +01:00
SmartDevice . GetSmartDeviceParameters ( ) +
2022-09-06 16:08:19 +02:00
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 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" +
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" +
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>
/// <param name="bikeId">Id of the bike to update locking state for.</param>
/// <param name="state">New locking state.</param>
2022-09-20 13:51:55 +02:00
/// <param name="versionInfo">Information about lock (firmware version, hardware version, ...).</param>
2022-09-06 16:08:19 +02:00
/// <returns>Request to update locking state.</returns>
public string UpateLockingState (
string bikeId ,
lock_state state ,
LocationDto geolocation ,
2022-09-20 13:51:55 +02:00
double batteryPercentage ,
IVersionInfo versionInfo )
2022-09-06 16:08:19 +02:00
= > "request=booking_update" +
GetBikeIdParameter ( bikeId ) +
GetLocationParameters ( geolocation ) +
GetLockStateParameter ( state ) +
GetBatteryPercentageParameters ( batteryPercentage ) +
2022-09-20 13:51:55 +02:00
GetVersionInfoParameter ( versionInfo ) +
2022-09-06 16:08:19 +02:00
AuthCookieParameter +
UiIsoLanguageNameParameter ;
/// <summary> Gets booking request request (synonym: booking == renting == mieten). </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bikeId">Id of the bike to book.</param>
/// <param name="guid">Used to publish GUID from app to copri. Used for initial setup of bike in copri.</param>
/// <param name="batteryPercentage">Holds the filling level percentage of the battery.</param>
2022-12-27 21:08:09 +01:00
/// <param name="nextAction">If not null next locking action which is performed after booking.</param>
2022-09-06 16:08:19 +02:00
/// <returns>Request to booking bike.</returns>
2022-12-27 21:08:09 +01:00
public string DoBook ( string bikeId , Guid guid , double batteryPercentage , LockingAction ? nextAction = null )
2022-09-06 16:08:19 +02:00
= > "request=booking_update" +
GetBikeIdParameter ( bikeId ) +
AuthCookieParameter +
$"&Ilockit_GUID={guid}" +
"&state=occupied" +
2022-12-27 21:08:09 +01:00
GetLockStateParameter ( nextAction . GetLockState ( ) ) +
2022-09-06 16:08:19 +02:00
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 BookAvailableAndStartOpening ( string bikeId )
= > "request=booking_request" +
GetBikeIdParameter ( bikeId ) +
AuthCookieParameter +
"&state=occupied" +
GetLockStateParameter ( lock_state . unlocking ) +
2023-02-22 14:03:35 +01:00
SmartDevice . GetSmartDeviceParameters ( ) +
2022-09-06 16:08:19 +02:00
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>
/// <param name="bikeId">Id of bike to return.</param>
/// <param name="geolocation">Geolocation of lock when returning bike.</param>
/// <returns>Requst on returning request.</returns>
2023-02-22 14:03:35 +01:00
public string DoReturn ( string bikeId , LocationDto geolocation )
2022-09-06 16:08:19 +02:00
= > "request=booking_update" +
GetBikeIdParameter ( bikeId ) +
AuthCookieParameter +
"&state=available" +
GetLocationParameters ( geolocation ) +
GetLockStateParameter ( lock_state . locked ) +
2023-02-22 14:03:35 +01:00
SmartDevice . GetSmartDeviceParameters ( ) +
2022-09-06 16:08:19 +02:00
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>
2023-02-22 14:03:35 +01:00
public string ReturnAndStartClosing ( string bikeId )
2022-09-06 16:08:19 +02:00
= > "request=booking_update" +
GetBikeIdParameter ( bikeId ) +
AuthCookieParameter +
"&state=available" +
GetLockStateParameter ( lock_state . locking ) +
2023-02-22 14:03:35 +01:00
SmartDevice . GetSmartDeviceParameters ( ) +
2022-09-06 16:08:19 +02:00
UiIsoLanguageNameParameter ;
/// <summary> Gets submit feedback request. </summary>
/// <param name="bikeId">Id of the bike to return.</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 ,
int? currentChargeBars = null ,
string message = null ,
bool isBikeBroken = false )
{
string GetIsBikeBroken ( )
= > isBikeBroken ? "&bike_broken=1" : string . Empty ;
string GetMessage ( )
= > ! string . IsNullOrEmpty ( message ) ? $"&message={WebUtility.UrlEncode(message)}" : string . Empty ;
string GetCurrentChargeBars ( )
= > currentChargeBars ! = null ? $"&charge_current_bars={currentChargeBars.Value}" : string . Empty ;
return "request=user_feedback" +
GetBikeIdParameter ( bikeId ) +
GetCurrentChargeBars ( ) +
GetIsBikeBroken ( ) +
GetMessage ( ) +
AuthCookieParameter +
UiIsoLanguageNameParameter ;
}
/// <summary>
/// Gets request for submiting mini survey to copri server.
/// </summary>
/// <param name="answers">Collection of answers.</param>
public string DoSubmitMiniSurvey ( IDictionary < string , string > answers )
{
// Remove entires which invalid keys or values.
var validAnsers = answers ? . Where ( x = > ! string . IsNullOrEmpty ( x . Key ? . Trim ( ) ) & & ! string . IsNullOrEmpty ( x . Value ? . Trim ( ) ) ) ;
// 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 ;
}
2023-01-18 14:22:51 +01:00
/// <summary>
/// Gets bike id parameter.
/// </summary>
/// <param name="bikeId">Id of bike.</param>
/// <returns>bike id parameter in a format which is urlencode invariant.</returns>
2022-09-06 16:08:19 +02:00
private static string GetBikeIdParameter ( string bikeId )
2023-01-18 14:22:51 +01:00
= > $"&bike={WebUtility.UrlEncode(bikeId)}" ;
2022-09-06 16:08:19 +02:00
2023-01-18 14:22:51 +01:00
/// <summary>
/// Gets parameter holding lock state or null if state is unknown.
/// </summary>
/// <param name="lockState">Null or state of lock.</param>
/// <returns>Lock state in a format which is urlencode invariant.</returns>
2022-12-27 21:08:09 +01:00
private static string GetLockStateParameter ( lock_state ? lockState )
= > lockState . HasValue ? $"&lock_state={lockState}" : string . Empty ;
2022-09-06 16:08:19 +02:00
2022-12-27 21:08:09 +01:00
/// <summary>
/// Gets the battery level percentage parameter if percentage is not NaN an empty string otherwise.
/// </summary>
2023-01-18 14:22:51 +01:00
/// <returns>Gets battery percentage parameters in a format which is urlencode invariant or an empty string if percentage percentge is NaN.</returns>
2022-09-06 16:08:19 +02:00
private static string GetBatteryPercentageParameters ( double batteryPercentage ) = > ! double . IsNaN ( batteryPercentage )
? $"&voltage={batteryPercentage.ToString(CultureInfo.InvariantCulture)}"
: string . Empty ;
2023-01-18 14:22:51 +01:00
/// <summary>
/// Gets the version info parameter or an empty string if version info is not available.
/// </summary>
/// <param name="versionInfo">Lock version info.</param>
/// <returns>Version info in a format which is urlencode invariant or empty. </returns>
2022-09-20 13:51:55 +02:00
private static string GetVersionInfoParameter ( IVersionInfo versionInfo ) = > versionInfo ? . FirmwareVersion > 0 | | versionInfo ? . HardwareVersion > 0 | | versionInfo ? . LockVersion > 0
2022-09-22 20:58:30 +02:00
? $"&firmware=HW%20{versionInfo.HardwareVersion}%3BFW%20{versionInfo.FirmwareVersion}%3BLock%20{versionInfo.LockVersion}"
2022-09-20 13:51:55 +02:00
: string . Empty ;
2022-09-06 16:08:19 +02:00
/// <summary> Gets the geolocation parameter. </summary>
/// <param name="geolocation">Geolocation or null.</param>
2023-01-18 14:22:51 +01:00
/// <returns>Empty string if geoloction is null otherwise parmeter including latitude, longitude and age in a format which is urlencode invariant.</returns>
2022-09-06 16:08:19 +02:00
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 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 ;
}
}
2021-05-13 20:03:07 +02:00
}