using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using TINK.Model.Bikes.BikeInfoNS.BluetoothLock; using TINK.Model.Device; using TINK.Repository.Exception; using TINK.Services.Logging; namespace TINK.Repository.Request { /// Creates requests if a user is logged in. public class RequestBuilderLoggedIn : IRequestBuilder { /// Constructs a object for building requests. /// /// Two letter ISO language name. public RequestBuilderLoggedIn( string merchantId, string uiIsoLangugageName, string sessionCookie) { 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)); UiIsoLanguageNameParameter = RequestBuilderHelper.GetLanguageParameter(uiIsoLangugageName); AuthCookieParameter = $"&authcookie={SessionCookie}{MerchantId}"; } /// Holds the id denoting the merchant (TINK app). public string MerchantId { get; } /// Holds the session cookie if a user is logged in. public string SessionCookie { get; } /// Holds the current ui two letter ISO language name. public string UiIsoLanguageNameParameter { get; } /// Auth cookie parameter. private string AuthCookieParameter { get; } /// Gets request to log user in. /// Mailaddress of user to log in. /// Password to log in. /// Id specifying user and hardware. /// Response which holds auth cookie public string DoAuthorization( string mailAddress, string password, string deviceId) => throw new CallNotRequiredException(); /// Logs user out. public string DoAuthout() => "request=authout" + AuthCookieParameter + UiIsoLanguageNameParameter; /// Gets bikes available. /// Request to query list of bikes available. public string GetBikesAvailable() => "request=bikes_available&system=all" + AuthCookieParameter + UiIsoLanguageNameParameter; /// Gets a list of bikes reserved/ booked by acctive user from Copri. /// Request to query list of bikes occupied. public string GetBikesOccupied() => "request=user_bikes_occupied&system=all&genkey=1" + AuthCookieParameter + UiIsoLanguageNameParameter; /// Get list of stations from file. /// Request to query list of station. public string GetStations() => "request=stations_available" + AuthCookieParameter + UiIsoLanguageNameParameter; /// Gets reservation request (synonym: reservation == request == reservieren). /// Operator specific call. /// Id of the bike to reserve. /// Requst to reserve bike. public string DoReserve(string bikeId) => "request=booking_request" + GetBikeIdParameter(bikeId) + AuthCookieParameter + UiIsoLanguageNameParameter; /// Gets request to cancel reservation. /// Operator specific call. /// Id of the bike to cancel reservation for. /// Requst on cancel booking request. public string DoCancelReservation(string bikeId) => "request=booking_cancel" + GetBikeIdParameter(bikeId) + AuthCookieParameter + UiIsoLanguageNameParameter; /// Request to get keys. /// Operator specific call. /// Id of the bike to get keys for. /// Request to get keys. public string CalculateAuthParameters(string bikeId) => "request=booking_update" + GetBikeIdParameter(bikeId) + AuthCookieParameter + "&genkey=1" + UiIsoLanguageNameParameter; /// Gets the request for notifying about start of returning sequence. /// Operator specific call. /// Id of the bike to return. /// Request to notify about start of returning sequence. public string StartReturningBike(string bikeId) => "request=booking_update" + GetBikeIdParameter(bikeId) + GetLockStateParameter(lock_state.locking) + AuthCookieParameter + UiIsoLanguageNameParameter; /// Gets the request for updating lock state for a booked bike. /// Operator specific call. /// Id of the bike to update locking state for. /// New locking state. /// Information about lock (firmware version, hardware version, ...). /// Request to update locking state. public string UpateLockingState( string bikeId, lock_state state, LocationDto geolocation, double batteryPercentage, IVersionInfo versionInfo) => "request=booking_update" + GetBikeIdParameter(bikeId) + GetLocationParameters(geolocation) + GetLockStateParameter(state) + GetBatteryPercentageParameters(batteryPercentage) + GetVersionInfoParameter(versionInfo) + AuthCookieParameter + UiIsoLanguageNameParameter; /// Gets booking request request (synonym: booking == renting == mieten). /// Operator specific call. /// Id of the bike to book. /// Used to publish GUID from app to copri. Used for initial setup of bike in copri. /// Holds the filling level percentage of the battery. /// Request to booking bike. public string DoBook(string bikeId, Guid guid, double batteryPercentage) => "request=booking_update" + GetBikeIdParameter(bikeId) + AuthCookieParameter + $"&Ilockit_GUID={guid}" + "&state=occupied" + GetLockStateParameter(lock_state.unlocked) + GetBatteryPercentageParameters(batteryPercentage) + UiIsoLanguageNameParameter; /// Gets the request to book and start opening the bike (synonym: booking == renting == mieten). /// Id of the bike to book. /// Request to booking bike. public string BookAvailableAndStartOpening(string bikeId) => "request=booking_request" + GetBikeIdParameter(bikeId) + AuthCookieParameter + "&state=occupied" + GetLockStateParameter(lock_state.unlocking) + UiIsoLanguageNameParameter; /// Gets the request to book and start opening the bike (synonym: booking == renting == mieten). /// Id of the bike to book. /// Request to booking bike. public string BookReservedAndStartOpening(string bikeId) => "request=booking_update" + GetBikeIdParameter(bikeId) + AuthCookieParameter + "&state=occupied" + GetLockStateParameter(lock_state.unlocking) + UiIsoLanguageNameParameter; /// Gets request for returning the bike. /// Operator specific call. /// Id of bike to return. /// Geolocation of lock when returning bike. /// Requst on returning request. public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice) => "request=booking_update" + GetBikeIdParameter(bikeId) + AuthCookieParameter + "&state=available" + GetLocationParameters(geolocation) + GetLockStateParameter(lock_state.locked) + GetSmartDeviceParameters(smartDevice) + GetLog() + UiIsoLanguageNameParameter; /// Returns a bike and starts closing. /// Id of the bike to return. /// Provides info about hard and software. /// Response to send to corpi. public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice) => "request=booking_update" + GetBikeIdParameter(bikeId) + AuthCookieParameter + "&state=available" + GetLockStateParameter(lock_state.locking) + GetSmartDeviceParameters(smartDevice) + UiIsoLanguageNameParameter; /// Gets submit feedback request. /// Id of the bike to return. /// General purpose message or error description. /// True if bike is broken. /// Submit feedback request. 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; } /// /// Gets request for submiting mini survey to copri server. /// /// Collection of answers. public string DoSubmitMiniSurvey(IDictionary 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; } 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; private static string GetVersionInfoParameter(IVersionInfo versionInfo) => versionInfo?.FirmwareVersion > 0 || versionInfo?.HardwareVersion > 0 || versionInfo?.LockVersion > 0 ? $"&firmware=HW%20{versionInfo.HardwareVersion}%3BFW%20{versionInfo.FirmwareVersion}%3BLock%20{versionInfo.LockVersion}" : string.Empty; /// Gets the geolocation parameter. /// Geolocation or null. 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}"; } /// Gets the geolocation parameter. /// Geolocation or null. 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; /// /// Gets logging entries from serilog. /// /// 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; } } }