diff --git a/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html b/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html
index e56447e..6c5e7aa 100644
--- a/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html
+++ b/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html
@@ -23,7 +23,7 @@
Version ACTIVE_APPNAME: CURRENT_VERSION_TINKAPP.
Entwickler
-
Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.
+
Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike
Verwendete Bibliotheken
diff --git a/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html b/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html
index e56447e..6c5e7aa 100644
--- a/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html
+++ b/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html
@@ -23,7 +23,7 @@
Version ACTIVE_APPNAME: CURRENT_VERSION_TINKAPP.
Entwickler
-
Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.
+
Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike
Verwendete Bibliotheken
diff --git a/TINK/TINK/HtmlResouces/V02/InfoLicenses.html b/TINK/TINK/HtmlResouces/V02/InfoLicenses.html
index e56447e..6c5e7aa 100644
--- a/TINK/TINK/HtmlResouces/V02/InfoLicenses.html
+++ b/TINK/TINK/HtmlResouces/V02/InfoLicenses.html
@@ -23,7 +23,7 @@
Version ACTIVE_APPNAME: CURRENT_VERSION_TINKAPP.
Entwickler
-
Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.
+
Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike
Verwendete Bibliotheken
diff --git a/TINKLib/Model/Connector/Command/Command.cs b/TINKLib/Model/Connector/Command/Command.cs
index 0dfe245..b839df7 100644
--- a/TINKLib/Model/Connector/Command/Command.cs
+++ b/TINKLib/Model/Connector/Command/Command.cs
@@ -36,36 +36,36 @@ namespace TINK.Model.Connector
/// If communication fails an exception is thrown.
///
public async Task DoLogin(
- string p_strMail,
- string p_strPassword,
- string p_strDeviceId)
+ string mail,
+ string password,
+ string deviceId)
{
- if (string.IsNullOrEmpty(p_strMail))
+ if (string.IsNullOrEmpty(mail))
{
throw new ArgumentNullException("Can not loging user. Mail address must not be null or empty.");
}
- if (string.IsNullOrEmpty(p_strPassword))
+ if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException("Can not loging user. Password must not be null or empty.");
}
- if (string.IsNullOrEmpty(p_strDeviceId))
+ if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException("Can not loging user. Device not be null or empty.");
}
- AuthorizationResponse l_oResponse;
+ AuthorizationResponse response;
try
{
- l_oResponse = (await CopriServer.DoAuthorizationAsync(p_strMail, p_strPassword, p_strDeviceId)).GetIsResponseOk(p_strMail);
+ response = (await CopriServer.DoAuthorizationAsync(mail, password, deviceId)).GetIsResponseOk(mail);
}
catch (System.Exception)
{
throw;
}
- var l_oAccount = l_oResponse.GetAccount(MerchantId, p_strMail, p_strPassword);
+ var l_oAccount = response.GetAccount(MerchantId, mail, password);
// Log in state changes. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs(l_oAccount.SessionCookie, l_oAccount.Mail));
@@ -83,9 +83,9 @@ namespace TINK.Model.Connector
///
/// Request to reserve a bike.
///
- /// Bike to book.
+ /// Bike to book.
public async Task DoReserve(
- Bikes.Bike.BC.IBikeInfoMutable p_oBike)
+ Bikes.Bike.BC.IBikeInfoMutable bike)
{
Log.ForContext().Error("Unexpected booking request detected. No user logged in.");
await Task.CompletedTask;
diff --git a/TINKLib/Model/Connector/FilteredConnectorFactory.cs b/TINKLib/Model/Connector/FilteredConnectorFactory.cs
index 8005f01..5121035 100644
--- a/TINKLib/Model/Connector/FilteredConnectorFactory.cs
+++ b/TINKLib/Model/Connector/FilteredConnectorFactory.cs
@@ -5,12 +5,13 @@ namespace TINK.Model.Connector
public static class FilteredConnectorFactory
{
/// Creates a filter object.
- ///
+ /// Filter to apply on stations and bikes.
+ /// Connector to connect to COPRI.
public static IFilteredConnector Create(IEnumerable group, IConnector connector)
{
return group != null
? (IFilteredConnector) new FilteredConnector(group, connector)
- : new NullFilterConnector(connector);
+ : new NullFilterConnector(connector); // Do not apply filtering.
}
}
}
diff --git a/TINKLib/Model/Connector/Updater/UpdaterJSON.cs b/TINKLib/Model/Connector/Updater/UpdaterJSON.cs
index ebae8d7..007895c 100644
--- a/TINKLib/Model/Connector/Updater/UpdaterJSON.cs
+++ b/TINKLib/Model/Connector/Updater/UpdaterJSON.cs
@@ -91,7 +91,7 @@ namespace TINK.Model.Connector
{
if (loginResponse == null)
{
- throw new ArgumentNullException("p_oLoginResponse");
+ throw new ArgumentNullException(nameof(loginResponse));
}
return new Account(
@@ -165,13 +165,13 @@ namespace TINK.Model.Connector
}
/// Gets bikes available from copri server response.
- /// Response to create collection from.
+ /// Response to create collection from.
/// New collection of available bikes.
public static BikeCollection GetBikesAvailable(
- this BikesAvailableResponse p_oBikesAvailableResponse)
+ this BikesAvailableResponse bikesAvailableResponse)
{
return GetBikesAll(
- p_oBikesAvailableResponse,
+ bikesAvailableResponse,
new BikesReservedOccupiedResponse(), // There are no occupied bikes.
string.Empty,
() => DateTime.Now);
@@ -198,8 +198,8 @@ namespace TINK.Model.Connector
public static BikeCollection GetBikesAll(
BikesAvailableResponse bikesAvailableResponse,
BikesReservedOccupiedResponse bikesOccupiedResponse,
- string p_strMail,
- Func p_oDateTimeProvider)
+ string mail,
+ Func dateTimeProvider)
{
var bikesDictionary = new Dictionary();
var duplicates = new Dictionary();
@@ -242,8 +242,8 @@ namespace TINK.Model.Connector
{
BikeInfo bikeInfo = BikeInfoFactory.Create(
bikeInfoResponse,
- p_strMail,
- p_oDateTimeProvider);
+ mail,
+ dateTimeProvider);
if (bikeInfo == null)
{
diff --git a/TINKLib/Model/TinkApp.cs b/TINKLib/Model/TinkApp.cs
index c69ea6c..4f56b24 100644
--- a/TINKLib/Model/TinkApp.cs
+++ b/TINKLib/Model/TinkApp.cs
@@ -147,7 +147,7 @@ namespace TINK.Model
public TinkApp(
Settings.Settings settings,
IStore accountStore,
- Func connectorFactory,
+ Func connectorFactory,
IServicesContainer geolocationServicesContainer,
ILocksService locksService,
ISmartDevice device,
diff --git a/TINKLib/Model/User/Account/AccountExtensions.cs b/TINKLib/Model/User/Account/AccountExtensions.cs
index 6920435..5adac6e 100644
--- a/TINKLib/Model/User/Account/AccountExtensions.cs
+++ b/TINKLib/Model/User/Account/AccountExtensions.cs
@@ -6,12 +6,12 @@ namespace TINK.Model.User.Account
public static class AccountExtensions
{
/// Gets information whether user is logged in or not from account object.
- /// Object to get information from.
+ /// Object to get information from.
/// True if user is logged in, false if not.
- public static bool GetIsLoggedIn(this IAccount p_oAccount)
+ public static bool GetIsLoggedIn(this IAccount account)
{
- return !string.IsNullOrEmpty(p_oAccount.Mail)
- && !string.IsNullOrEmpty(p_oAccount.SessionCookie);
+ return !string.IsNullOrEmpty(account.Mail)
+ && !string.IsNullOrEmpty(account.SessionCookie);
}
///
diff --git a/TINKLib/Model/User/Account/AccountMutable.cs b/TINKLib/Model/User/Account/AccountMutable.cs
index 3323eea..d90947a 100644
--- a/TINKLib/Model/User/Account/AccountMutable.cs
+++ b/TINKLib/Model/User/Account/AccountMutable.cs
@@ -12,10 +12,6 @@ namespace TINK.Model.User.Account
///
private Account m_oAccount;
- /// Prevents an invalid instance to be created.
- private AccountMutable()
- {
- }
public AccountMutable(IAccount p_oSource)
{
diff --git a/TINKLib/Model/User/User.cs b/TINKLib/Model/User/User.cs
index 6d1b079..fe82673 100644
--- a/TINKLib/Model/User/User.cs
+++ b/TINKLib/Model/User/User.cs
@@ -13,15 +13,13 @@ namespace TINK.Model.User
///
public class User : IUser
{
- ///
- /// Holds account data.
- ///
- private readonly AccountMutable m_oAccount;
+ /// Holds account data.
+ private AccountMutable Account { get; }
///
/// Provides storing functionality.
///
- private IStore m_oStore;
+ private IStore Store { get; }
/// Holds the id of the device.
public string DeviceId { get; }
@@ -34,10 +32,10 @@ namespace TINK.Model.User
IAccount account,
string deviceId)
{
- m_oStore = accountStore
+ Store = accountStore
?? throw new ArgumentException("Can not instantiate user- object. No store functionality available.");
DeviceId = deviceId;
- m_oAccount = new AccountMutable(account);
+ Account = new AccountMutable(account);
}
/// Is fired wheneverlogin state changes.
@@ -46,19 +44,14 @@ namespace TINK.Model.User
///
/// Holds a value indicating whether user is logged in or not.
///
- public bool IsLoggedIn {
- get
- {
- return m_oAccount.GetIsLoggedIn();
- }
- }
+ public bool IsLoggedIn => Account.GetIsLoggedIn();
///
/// Holds the mail address.
///
public string Mail
{
- get { return m_oAccount.Mail; }
+ get { return Account.Mail; }
}
///
@@ -66,24 +59,24 @@ namespace TINK.Model.User
///
public string SessionCookie
{
- get { return m_oAccount.SessionCookie; }
+ get { return Account.SessionCookie; }
}
///
/// Holds the password.
///
public string Password
{
- get { return m_oAccount.Pwd; }
+ get { return Account.Pwd; }
}
/// Holds the debug level.
public Permissions DebugLevel
{
- get { return m_oAccount.DebugLevel; }
+ get { return Account.DebugLevel; }
}
/// Holds the group of the bike (TINK, Konrad, ...).
- public IEnumerable Group { get { return m_oAccount.Group; } }
+ public IEnumerable Group { get { return Account.Group; } }
/// Logs in user.
/// Account to use for login.
@@ -93,7 +86,7 @@ namespace TINK.Model.User
{
if (IsLoggedIn)
{
- throw new Exception($"Can not log in user {mail} because user {m_oAccount} is already logged in.");
+ throw new Exception($"Can not log in user {mail} because user {Account} is already logged in.");
}
// Check if password might be valid before connecting to copri.
@@ -113,10 +106,10 @@ namespace TINK.Model.User
public async Task Login(IAccount account)
{
// Update account instance from copri data.
- m_oAccount.Copy(account);
+ Account.Copy(account);
// Save data to store.
- await m_oStore.Save(m_oAccount);
+ await Store.Save(Account);
// Nothing to do because state did not change.
StateChanged?.Invoke(this, new EventArgs());
@@ -128,7 +121,7 @@ namespace TINK.Model.User
{
var l_oPreviousState = IsLoggedIn;
- m_oAccount.Copy(m_oStore.Delete(m_oAccount));
+ Account.Copy(Store.Delete(Account));
if (IsLoggedIn == l_oPreviousState)
{
@@ -144,11 +137,11 @@ namespace TINK.Model.User
/// Some user may be "TINK"- user only, some "Konrad" and some may be "TINK" and "Konrad" users.
///
/// Account to filter with.
- /// Groups to filter..
+ /// Groups to filter..
/// Filtered bike groups.
- public IEnumerable DoFilter(IEnumerable p_oSource = null)
+ public IEnumerable DoFilter(IEnumerable source = null)
{
- return m_oAccount.DoFilter(p_oSource);
+ return Account.DoFilter(source);
}
}
}
diff --git a/TINKLib/Repository/CopriCallsMemory.cs b/TINKLib/Repository/CopriCallsMemory.cs
index 629ab20..9fbb72a 100644
--- a/TINKLib/Repository/CopriCallsMemory.cs
+++ b/TINKLib/Repository/CopriCallsMemory.cs
@@ -1264,7 +1264,7 @@ namespace TINK.Repository
}
}";
- private const SampleSets DEFAULT_SAMPLE_SET = SampleSets.Set2;
+ private const SampleSets DEFAULT_SAMPLE_SET = SampleSets.Set2;
private const int DEFAULT_STAGE_INDEX = 1;
diff --git a/TestShareeLib/Model/TestTinkApp.cs b/TestShareeLib/Model/TestTinkApp.cs
index 7d1b8bf..10240d4 100644
--- a/TestShareeLib/Model/TestTinkApp.cs
+++ b/TestShareeLib/Model/TestTinkApp.cs
@@ -2,9 +2,7 @@
using System;
using TINK.Model;
using TINK.Model.Connector;
-using TINK.Repository;
using TINK.Model.Services.CopriApi.ServerUris;
-using static TINK.Repository.CopriCallsMemory;
using TINK.Services;
using NSubstitute;
using TINK.Model.Services.Geolocation;
@@ -12,8 +10,8 @@ using TINK.Services.BluetoothLock;
using TINK.Model.Device;
using TINK.Model.User.Account;
using Plugin.Permissions.Abstractions;
-using System.Threading.Tasks;
-using System.Collections.Generic;
+
+using TestShareeLib.Repository;
namespace TestTINKLib.Fixtures.UseCases.Logout
{
@@ -32,9 +30,8 @@ namespace TestTINKLib.Fixtures.UseCases.Logout
accountStore.Load().Returns(account);
account.Mail.Returns("javaminister@gmail.com");
- account.Pwd.Returns("javaminister");
- account.SessionCookie.Returns("4da3044c8657a04ba60e2eaa753bc51a");
- account.Group.Returns(new List { "TINK" });
+ account.Pwd.Returns("*********");
+ account.SessionCookie.Returns("6103_112e96b36ba33de245943c5ffaf369cd_");
// No user logged in is initial state to verify.
var l_oTinkApp = new TinkApp(
@@ -44,8 +41,8 @@ namespace TestTINKLib.Fixtures.UseCases.Logout
activeUri: new Uri(CopriServerUriList.TINK_DEVEL)),
accountStore,
(isConnected, uri, sessionCookie, mail, expiresAfter) => string.IsNullOrEmpty(sessionCookie)
- ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1))
- : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
+ ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001())
+ : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001(sessionCookie)),
Substitute.For>(),
locksService,
device,
@@ -57,17 +54,29 @@ namespace TestTINKLib.Fixtures.UseCases.Logout
lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to
Assert.IsTrue(l_oTinkApp.ActiveUser.IsLoggedIn);
- Assert.AreEqual(13, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
- Assert.AreEqual(2, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
- Assert.AreEqual("4da3044c8657a04ba60e2eaa753bc51a", l_oTinkApp.GetConnector(true).Command.SessionCookie);
+ // There are 6 bikes available and 2, one reserved and one rented by javaminsiter.
+ Assert.AreEqual(
+ 8,
+ l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
+ "Sum of bikes is 6 occupied plus 2 occupied.");
+ Assert.AreEqual(2,
+ l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
+ "Javaminster occupies 2 bikes.");
+ Assert.AreEqual("6103_112e96b36ba33de245943c5ffaf369cd_", l_oTinkApp.GetConnector(true).Command.SessionCookie);
// Log user out.
l_oTinkApp.GetConnector(true).Command.DoLogout().Wait();
l_oTinkApp.ActiveUser.Logout();
Assert.IsFalse(l_oTinkApp.ActiveUser.IsLoggedIn);
- Assert.AreEqual(11, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
- Assert.AreEqual(0, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
+ Assert.AreEqual(
+ 6,
+ l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
+ "Sum of bikes is 6 occupied, no one occupied because no user is logged in");
+ Assert.AreEqual(
+ 0,
+ l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
+ "If no user is logged in no occupied bikes are shown.");
Assert.IsNull(l_oTinkApp.GetConnector(true).Command.SessionCookie);
}
}
diff --git a/TestShareeLib/Model/TestTinkAppLogin.cs b/TestShareeLib/Model/TestTinkAppLogin.cs
index 5c35e43..ccb1638 100644
--- a/TestShareeLib/Model/TestTinkAppLogin.cs
+++ b/TestShareeLib/Model/TestTinkAppLogin.cs
@@ -13,10 +13,10 @@ using TINK.Model.Device;
using TINK.Model.User.Account;
using Plugin.Permissions.Abstractions;
using System.Threading.Tasks;
+using TestShareeLib.Repository;
namespace TestTINKLib.Fixtures.UseCases.Login
{
-
[TestFixture]
public class TestTinkApp
{
@@ -37,8 +37,8 @@ namespace TestTINKLib.Fixtures.UseCases.Login
activeUri: new Uri(CopriServerUriList.TINK_DEVEL)),
accountStore,
(isConnected, uri, sessionCookie, mail, expiresAfter) => string.IsNullOrEmpty(sessionCookie)
- ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1)) as IConnector
- : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
+ ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001()) as IConnector
+ : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001(sessionCookie)),
Substitute.For>(),
locksService,
device,
@@ -50,18 +50,30 @@ namespace TestTINKLib.Fixtures.UseCases.Login
lastVersion: new Version(3, 0, 173) /* Current app version. Must be larger or equal 3.0.173 to lastVersion*/);
Assert.IsFalse(l_oTinkApp.ActiveUser.IsLoggedIn);
- Assert.AreEqual(11, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
- Assert.AreEqual(0, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
+ Assert.AreEqual(
+ 6,
+ l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
+ "Sum of bikes is 6 occupied, no one occupied because no user is logged in");
+ Assert.AreEqual(
+ 0,
+ l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
+ "If no user is logged in no occupied bikes are shown.");
Assert.IsNull(l_oTinkApp.GetConnector(true).Command.SessionCookie);
// Log user out.
- var l_oAccount = l_oTinkApp.GetConnector(true).Command.DoLogin("javaminister@gmail.com", "javaminister", "HwId1000000000000").Result;
+ var l_oAccount = l_oTinkApp.GetConnector(true).Command.DoLogin("javaminister@gmail.com", "*********", "HwId1000000000000").Result;
await l_oTinkApp.ActiveUser.Login(l_oAccount);
Assert.IsTrue(l_oTinkApp.ActiveUser.IsLoggedIn);
- Assert.AreEqual(13, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count);
- Assert.AreEqual(2, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count);
- Assert.AreEqual("4da3044c8657a04ba60e2eaa753bc51a", l_oTinkApp.GetConnector(true).Command.SessionCookie);
+ Assert.AreEqual(
+ 8,
+ l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count,
+ "Sum of bikes is 6 occupied plus 2 occupied.");
+ Assert.AreEqual(
+ 2,
+ l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count,
+ "Javaminster occupies 2 bikes.");
+ Assert.AreEqual("6103_112e96b36ba33de245943c5ffaf369cd_", l_oTinkApp.GetConnector(true).Command.SessionCookie);
}
}
}
diff --git a/TestShareeLib/Repository/CopriCallMemoryBase.cs b/TestShareeLib/Repository/CopriCallMemoryBase.cs
new file mode 100644
index 0000000..c9e2aa9
--- /dev/null
+++ b/TestShareeLib/Repository/CopriCallMemoryBase.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using TINK.Model;
+using TINK.Model.Device;
+using TINK.Repository;
+using TINK.Repository.Request;
+using TINK.Repository.Response;
+
+namespace TestShareeLib.Repository
+{
+ /// Provides functionality for keeping a set of COPRI responses.
+ public abstract class CopriCallMemoryBase
+ {
+ private string BikesAvailableResponse { get; }
+
+ private string BikesOccupiedResponse { get; }
+
+ private string AuthResponse { get; }
+
+ private string AuthOutResponse { get; }
+
+ private string Stations { get; }
+
+ private string BookingRequestResponse { get; }
+
+ private string CancelBookingRequestResponse { get; }
+
+ private IRequestBuilder requestBuilder;
+
+ public CopriCallMemoryBase(
+ string bikesAvailableResponse = null,
+ string bikesOccupiedResponse = null,
+ string authResponse = null,
+ string authOutResponse = null,
+ string stations = null,
+ string bookingRequestResponse = null,
+ string cancelBookingRequestResponse = null,
+ string sessionCookie = null)
+ {
+ SessionCookie = sessionCookie;
+
+ BikesAvailableResponse = bikesAvailableResponse;
+ BikesOccupiedResponse = bikesOccupiedResponse;
+ AuthResponse = authResponse;
+ AuthOutResponse = authOutResponse;
+ BookingRequestResponse = bookingRequestResponse;
+ CancelBookingRequestResponse = cancelBookingRequestResponse;
+
+ Stations = stations;
+
+ requestBuilder = string.IsNullOrEmpty(sessionCookie)
+ ? new RequestBuilder(MerchantId) as IRequestBuilder
+ : new RequestBuilderLoggedIn(MerchantId, sessionCookie);
+
+ }
+
+ /// Holds the session id of the logged in user, null otherwise.
+ public string SessionCookie { get; private set; }
+
+ /// Logs user in.
+ /// User to log in.
+ /// Id specifying user and hardware.
+ /// Mailaddress of user to log in.
+ /// Password to log in.
+ /// Response which holds auth cookie
+ public async Task DoAuthorizationAsync(
+ string mailAddress,
+ string password,
+ string deviceId)
+ => await Task.Run(() => DoAuthorize(AuthResponse, mailAddress, password, deviceId));
+
+ /// Logs user out.
+ /// User to log in.
+ /// Response which holds auth cookie
+ public async Task DoAuthoutAsync()
+ => await Task.Run(() => DoAuthout(AuthOutResponse, SessionCookie));
+
+ ///
+ /// Gets list of bikes from memory.
+ ///
+ ///
+ public async Task GetBikesAvailableAsync()
+ => await Task.Run(() => GetBikesAvailable(BikesAvailableResponse, null, SessionCookie));
+
+ ///
+ /// Gets a list of bikes reserved/ booked by acctive user from Copri.
+ ///
+ /// Cookie to authenticate user.
+ /// Response holding list of bikes.
+ public async Task GetBikesOccupiedAsync()
+ {
+ try
+ {
+ requestBuilder.GetBikesOccupied(); // Non mock implementation if ICopriServer call this member as well. To ensure comparable behaviour this member is called here as well.
+ }
+ catch (NotSupportedException)
+ {
+ // No user logged in.
+ await Task.CompletedTask;
+ return ResponseHelper.GetBikesOccupiedNone();
+ }
+ return await Task.Run(() => GetBikesOccupied(BikesOccupiedResponse, SessionCookie));
+ }
+
+ ///
+ /// Get list of stations from file.
+ ///
+ /// Auto cookie of user if user is logged in.
+ /// List of files.
+ public async Task GetStationsAsync()
+ => await Task.Run(() => GetStationsAll(Stations, null, SessionCookie));
+
+ ///
+ /// Gets booking request response.
+ ///
+ /// Id of the bike to book.
+ /// Booking response.
+ public async Task DoReserveAsync(string bikeId, Uri operatorUri)
+ => await Task.Run(() => DoReserve(BookingRequestResponse, bikeId, SessionCookie));
+
+ ///
+ /// Gets canel booking request response.
+ ///
+ /// Id of the bike to book.
+ /// Cookie of the logged in user.
+ /// Response on cancel booking request.
+ public async Task DoCancelReservationAsync(string bikeId, Uri operatorUri)
+ => await Task.Run(() => DoCancelReservation(CancelBookingRequestResponse, bikeId, SessionCookie));
+
+
+ /// Gets the merchant id.
+ public string MerchantId => TinkApp.MerchantId;
+
+ /// Returns false because cached values are returned.
+ public bool IsConnected => false;
+
+ /// Logs user in.
+ /// User to log in.
+ /// Id specifying user and hardware.
+ /// Mailaddress of user to log in.
+ /// Password to log in.
+ /// Response which holds auth cookie
+ public static AuthorizationResponse DoAuthorize(
+ string DoAuthResponse,
+ string p_strMailAddress,
+ string p_strPassword,
+ string p_strDeviceId)
+ {
+ return p_strMailAddress == "javaminister@gmail.com"
+ && p_strPassword == "*********" &&
+ p_strDeviceId == "HwId1000000000000"
+ ? JsonConvertRethrow.DeserializeObject>(DoAuthResponse).shareejson
+ : JsonConvertRethrow.DeserializeObject>(DO_AUTH_Unknown_User_FILE).shareejson;
+
+ }
+
+ /// Logs user in.
+ /// Response which holds auth cookie
+ public static AuthorizationoutResponse DoAuthout(
+ string authOutResponse,
+ string sessionCookie)
+ {
+ // Response contains auth cookie of user "JavaministerHardwareNr1"
+ // For this reason do not return answer if mail and pwd do not match.
+
+ return !string.IsNullOrEmpty(sessionCookie)
+ ? JsonConvertRethrow.DeserializeObject>(authOutResponse).shareejson
+ : throw new NotSupportedException();
+
+ }
+
+ ///
+ /// Gets list of bikes from memory.
+ ///
+ /// Id of the merchant.
+ /// Auto cookie of user if user is logged in.
+ /// Set of samples.
+ /// Index of the stage.
+ ///
+ public static BikesAvailableResponse GetBikesAvailable(
+ string BikesAvailableResponse,
+ string p_strMerchantId,
+ string p_strSessionCookie = null) => CopriCallsStatic.DeserializeResponse(BikesAvailableResponse);
+
+ ///
+ /// Gets stations response.
+ ///
+ /// Id of the merchant.
+ /// Auto cookie of user if user is logged in.
+ ///
+ ///
+ ///
+ public static StationsAvailableResponse GetStationsAll(
+ string stations,
+ string merchantId,
+ string cookie = null)
+ => JsonConvertRethrow.DeserializeObject>(stations).shareejson;
+
+ ///
+ /// Gets booking request response.
+ ///
+ /// Id of the bike.
+ /// Identifies the logged in user.
+ /// Sample set to use.
+ /// Index of the stage.
+ ///
+ public static ReservationBookingResponse DoReserve(
+ string bookingRequestResponse,
+ string bikeId,
+ string sessionCookie)
+ => JsonConvertRethrow.DeserializeObject>(bookingRequestResponse).shareejson;
+
+ ///
+ /// Gets canel booking request response.
+ ///
+ /// Id of the bike to book.
+ /// Cookie of the logged in user.
+ /// Response on cancel booking request.
+ public static ReservationCancelReturnResponse DoCancelReservation(
+ string cancelBookingRequestResponse,
+ string bikeId,
+ string cookie)
+ => JsonConvertRethrow.DeserializeObject>(cancelBookingRequestResponse).shareejson;
+
+ public Task CalculateAuthKeysAsync(string bikeId, Uri operatorUri)
+ => null;
+
+ public Task UpdateLockingStateAsync(
+ string bikeId,
+ LocationDto geolocation,
+ lock_state state,
+ double batteryLevel,
+ Uri operatorUri)
+ => null;
+
+ public Task DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri)
+ => null;
+
+ public Task DoReturn(
+ string bikeId,
+ LocationDto geolocation,
+ ISmartDevice smartDevice,
+ Uri operatorUri)
+ => null;
+
+ public Task DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri)
+ => null;
+
+ /// Submits mini survey to copri server.
+ /// Collection of answers.
+ public Task DoSubmitMiniSurvey(IDictionary answers)
+ => null;
+
+ ///
+ /// Gets a list of bikes reserved/ booked by acctive user from Copri.
+ ///
+ /// Cookie to authenticate user.
+ /// Sample set to use.
+ /// Index of the stage.
+ /// Response holding list of bikes.
+ public static BikesReservedOccupiedResponse GetBikesOccupied(
+ string bikesOccupied,
+ string sessionCookie = null)
+ {
+ var response = CopriCallsStatic.DeserializeResponse(bikesOccupied);
+ return sessionCookie != null && (response?.authcookie?.Contains(sessionCookie) ?? false)
+ ? response
+ : ResponseHelper.GetBikesOccupiedNone(sessionCookie);
+
+ }
+
+ public const string DO_AUTH_Unknown_User_FILE = @"
+ {
+ ""shareejson"" : {
+ ""response"" : ""authorization"",
+ ""authcookie"" : 0,
+ ""response_state"" : ""Failure: cannot generate authcookie"",
+ ""apiserver"" : ""https://tinkwwp.copri-bike.de""
+ }
+ }";
+ }
+}
diff --git a/TestShareeLib/Repository/CopriCallsMemory001.cs b/TestShareeLib/Repository/CopriCallsMemory001.cs
new file mode 100644
index 0000000..ebd7319
--- /dev/null
+++ b/TestShareeLib/Repository/CopriCallsMemory001.cs
@@ -0,0 +1,403 @@
+using TINK.Repository;
+
+namespace TestShareeLib.Repository
+{
+ ///
+ /// Holds some COPRI responses for testing purposes.
+ ///
+ /// Holds some demo Meinkonrad and LastenradBayern bikes
+ ///
+ public class CopriCallsMemory001 : CopriCallMemoryBase, ICopriServer
+ {
+ public CopriCallsMemory001(string sessionCookie = null) : base(
+ bikesAvailableResponse: BikesAvailableResponse,
+ bikesOccupiedResponse: BikesOccupiedResponse,
+ authResponse: AuthResponse,
+ authOutResponse: AuthOutResponse,
+ sessionCookie: sessionCookie)
+ { }
+
+ private static string AuthResponse => @"{
+ ""shareejson"": {
+ ""clearing_cache"": ""0"",
+ ""privacy_html"": ""site/privacy.html"",
+ ""user_id"": ""javaminister@gmail.com"",
+ ""impress_html"": ""site/impress.html"",
+ ""tariff_info_html"": ""site/tariff_info_1.html"",
+ ""lang"": ""DE"",
+ ""last_used_operator"": {
+ ""operator_name"": ""sharee.bike | TeilRad GmbH"",
+ ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
+ ""operator_phone"": ""+49 761 45370097"",
+ ""operator_email"": ""hotline@sharee.bike"",
+ ""operator_color"": ""#009699""
+ },
+ ""response"": ""authorization"",
+ ""agb_checked"": ""0"",
+ ""agb_html"": ""site/agb.html"",
+ ""response_text"": ""Herzlich willkommen im Fahrradmietsystem"",
+ ""bike_info_html"": ""site/bike_info.html"",
+ ""debuglevel"": ""1"",
+ ""uri_primary"": ""https://shareeapp-primary.copri.eu"",
+ ""response_state"": ""OK, nothing todo"",
+ ""new_authcoo"": ""1"",
+ ""user_tour"": [],
+ ""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"",
+ ""copri_version"": ""4.1.8.21"",
+ ""apiserver"": ""https://shareeapp-fr01.copri.eu"",
+ ""user_group"": []
+ }
+ }";
+
+ private static string AuthOutResponse = @"{
+ ""shareejson"": {
+ ""copri_version"": ""4.1.8.21"",
+ ""authcookie"": ""1"",
+ ""user_tour"": [],
+ ""user_group"": null,
+ ""apiserver"": ""https://shareeapp-fr01.copri.eu"",
+ ""debuglevel"": ""1"",
+ ""uri_primary"": ""https://shareeapp-primary.copri.eu"",
+ ""bike_info_html"": ""site/bike_info.html"",
+ ""response_state"": ""OK, logout"",
+ ""new_authcoo"": ""0"",
+ ""lang"": ""DE"",
+ ""last_used_operator"": {
+ ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
+ ""operator_name"": ""sharee.bike | TeilRad GmbH"",
+ ""operator_email"": ""hotline@sharee.bike"",
+ ""operator_phone"": ""+49 761 45370097"",
+ ""operator_color"": ""#009699""
+ },
+ ""tariff_info_html"": ""site/tariff_info_1.html"",
+ ""impress_html"": ""site/impress.html"",
+ ""response_text"": ""Auf Wiedersehen."",
+ ""agb_html"": ""site/agb.html"",
+ ""response"": ""authout"",
+ ""agb_checked"": ""0"",
+ ""privacy_html"": ""site/privacy.html"",
+ ""clearing_cache"": ""0"",
+ ""user_id"": ""javaminister@gmail.com""
+ }
+ }";
+
+ private static string BikesOccupiedResponse => @"{
+ ""shareejson"": {
+ ""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"",
+ ""copri_version"": ""4.1.8.21"",
+ ""user_tour"": [],
+ ""user_group"": [
+ ""FR300103"",
+ ""FR300101""
+ ],
+ ""bikes_occupied"": {
+ ""157056"": {
+ ""K_seed"": ""[-20, -104, -112, -49, 3, -74, -43, -115, -53, 34, -48, -29, -64, -90, -26, -74]"",
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
+ ""bike"": ""FR1544"",
+ ""unit_price"": ""3.00"",
+ ""description"": ""Contributor-Paul"",
+ ""station"": ""FR103"",
+ ""request_time"": ""2021-11-06 18:57:20.034438+01"",
+ ""Ilockit_ID"": ""ISHAREIT-2200544"",
+ ""total_price"": ""25.50"",
+ ""bike_group"": [
+ ""FR300103""
+ ],
+ ""K_u"": ""[43, -16, 72, -5, 23, -117, 43, 57, 124, -106, -115, 97, -93, -30, -34, -7, -21, 119, 109, 92, 0, 0, 0, 0]"",
+ ""computed_hours"": ""8.50"",
+ ""end_time"": ""2021-11-08 21:14:35"",
+ ""state"": ""occupied"",
+ ""tariff_description"": {
+ ""eur_per_hour"": ""3.00"",
+ ""number"": ""5494"",
+ ""max_eur_per_day"": ""10.00"",
+ ""name"": ""Tester Basic"",
+ ""free_hours"": ""0.50"",
+ ""track_info"": ""Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!"",
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB).""
+ },
+ ""lock_state"": ""locked"",
+ ""system"": ""Ilockit"",
+ ""gps"": {
+ ""latitude"": ""47.9994661873206"",
+ ""longitude"": ""7.7904340904206""
+ },
+ ""real_hours"": ""50.2833333333333"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-dc969f648732"",
+ ""start_time"": ""2021-11-06 18:57:25.445447+01""
+ },
+ ""157072"": {
+ ""bike"": ""FR1004"",
+ ""K_seed"": ""[-31, -81, -41, 95, 112, -113, -78, -22, 84, -112, -73, 31, -125, -49, 125, 10]"",
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
+ ""bike_group"": [
+ ""FR300103""
+ ],
+ ""total_price"": ""0.00"",
+ ""description"": ""Contributor-Recumbent"",
+ ""station"": ""FR103"",
+ ""request_time"": ""2021-11-08 21:10:24.829395+01"",
+ ""Ilockit_ID"": ""ISHAREIT-2302373"",
+ ""unit_price"": ""3.00"",
+ ""end_time"": ""2021-11-08 21:10:00+01"",
+ ""state"": ""requested"",
+ ""tariff_description"": {
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."",
+ ""free_hours"": ""0.50"",
+ ""name"": ""Tester Basic"",
+ ""max_eur_per_day"": ""10.00"",
+ ""eur_per_hour"": ""3.00"",
+ ""number"": ""5494""
+ },
+ ""computed_hours"": ""0"",
+ ""K_u"": ""[126, -125, 125, 83, 104, -121, -80, 40, 77, -35, 81, 27, 89, -124, -37, 57, 118, -113, 71, -37, 0, 0, 0, 0]"",
+ ""start_time"": ""2021-11-08 21:10:24.829395+01"",
+ ""gps"": {
+ ""latitude"": ""47.9980777"",
+ ""longitude"": ""7.7848769""
+ },
+ ""lock_state"": ""locked"",
+ ""system"": ""Ilockit"",
+ ""real_hours"": ""0"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-fe3962c08bcc""
+ }
+ },
+ ""apiserver"": ""https://shareeapp-fr01.copri.eu"",
+ ""uri_primary"": ""https://shareeapp-primary.copri.eu"",
+ ""debuglevel"": ""1"",
+ ""bike_info_html"": ""site/bike_info.html"",
+ ""new_authcoo"": ""0"",
+ ""response_state"": ""OK, nothing todo"",
+ ""last_used_operator"": {
+ ""operator_color"": ""#008dd2"",
+ ""operator_phone"": ""+49 089 / 111111111"",
+ ""operator_email"": ""hotline@lastenraddemo.bayern"",
+ ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
+ ""operator_name"": ""Lastenrad Bayern"",
+ ""operator_logo"": """"
+ },
+ ""lang"": ""DE"",
+ ""impress_html"": ""site/impress.html"",
+ ""tariff_info_html"": ""site/tariff_info_1.html"",
+ ""agb_html"": ""site/agb.html"",
+ ""response"": ""user_bikes_occupied"",
+ ""agb_checked"": ""1"",
+ ""privacy_html"": ""site/privacy.html"",
+ ""clearing_cache"": ""0"",
+ ""user_id"": ""ohauff@posteo.de""
+ }
+ }";
+
+ private static string BikesAvailableResponse => @"{
+ ""shareejson"": {
+ ""agb_checked"": ""1"",
+ ""response"": ""bikes_available"",
+ ""agb_html"": ""site/agb.html"",
+ ""impress_html"": ""site/impress.html"",
+ ""tariff_info_html"": ""site/tariff_info_1.html"",
+ ""lang"": ""DE"",
+ ""last_used_operator"": {
+ ""operator_color"": ""#008dd2"",
+ ""operator_email"": ""hotline@lastenraddemo.bayern"",
+ ""operator_phone"": ""+49 089 / 111111111"",
+ ""operator_name"": ""Lastenrad Bayern"",
+ ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
+ ""operator_logo"": """"
+ },
+ ""user_id"": ""ohauff@posteo.de"",
+ ""clearing_cache"": ""0"",
+ ""privacy_html"": ""site/privacy.html"",
+ ""bikes"": {
+ ""FR1543"": {
+ ""system"": ""Ilockit"",
+ ""gps"": {
+ ""longitude"": ""7.8255321"",
+ ""latitude"": ""47.9767121""
+ },
+ ""lock_state"": ""locked"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-cc141a6f68bb"",
+ ""state"": ""available"",
+ ""tariff_description"": {
+ ""free_hours"": ""0.50"",
+ ""name"": ""Tester Basic"",
+ ""eur_per_hour"": ""3.00"",
+ ""number"": ""5494"",
+ ""1543"": {
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB).""
+ },
+ ""max_eur_per_day"": ""10.00""
+ },
+ ""bike_group"": [
+ ""FR300103""
+ ],
+ ""station"": ""FR101"",
+ ""description"": ""Contributor-bike Dominik"",
+ ""Ilockit_ID"": ""ISHAREIT-2200543"",
+ ""authed"": ""1"",
+ ""bike"": ""FR1543"",
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu""
+ },
+ ""FR1003"": {
+ ""bike"": ""FR1003"",
+ ""authed"": ""1"",
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
+ ""bike_group"": [
+ ""FR300101""
+ ],
+ ""Ilockit_ID"": ""ISHAREIT-2200545"",
+ ""station"": ""FR101"",
+ ""description"": ""Stadtrad"",
+ ""tariff_description"": {
+ ""max_eur_per_day"": ""10.00"",
+ ""number"": ""5491"",
+ ""eur_per_hour"": ""2.00"",
+ ""1003"": {
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB).""
+ },
+ ""free_hours"": ""0.50"",
+ ""name"": ""Vauban Basic""
+ },
+ ""state"": ""available"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-e38bf9d32234"",
+ ""system"": ""Ilockit"",
+ ""gps"": {
+ ""longitude"": ""7.8255772"",
+ ""latitude"": ""47.9765188""
+ },
+ ""lock_state"": ""locked""
+ },
+ ""FR1540"": {
+ ""bike_group"": [
+ ""FR300103""
+ ],
+ ""Ilockit_ID"": ""ISHAREIT-2200540"",
+ ""description"": ""Contributor-bike Dieter"",
+ ""station"": ""FR101"",
+ ""bike"": ""FR1540"",
+ ""authed"": ""1"",
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-fc3c002a2add"",
+ ""system"": ""Ilockit"",
+ ""gps"": {
+ ""longitude"": ""7.8256267"",
+ ""latitude"": ""47.976803""
+ },
+ ""lock_state"": ""locked"",
+ ""tariff_description"": {
+ ""1540"": {
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB).""
+ },
+ ""free_hours"": ""0.50"",
+ ""name"": ""Tester Basic"",
+ ""max_eur_per_day"": ""10.00"",
+ ""eur_per_hour"": ""3.00"",
+ ""number"": ""5494""
+ },
+ ""state"": ""available""
+ },
+ ""FR1002"": {
+ ""bike_group"": [
+ ""FR300101""
+ ],
+ ""description"": ""Lasten-Dreirad"",
+ ""station"": ""FR101"",
+ ""Ilockit_ID"": ""ISHAREIT-2200539"",
+ ""authed"": ""1"",
+ ""bike"": ""FR1002"",
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
+ ""gps"": {
+ ""latitude"": ""47.976552"",
+ ""longitude"": ""7.8255068""
+ },
+ ""system"": ""Ilockit"",
+ ""lock_state"": ""locked"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-f0b4a692e169"",
+ ""state"": ""available"",
+ ""tariff_description"": {
+ ""max_eur_per_day"": ""10.00"",
+ ""1002"": {
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB).""
+ },
+ ""eur_per_hour"": ""2.00"",
+ ""number"": ""5491"",
+ ""free_hours"": ""0.50"",
+ ""name"": ""Vauban Basic""
+ }
+ },
+ ""FR1538"": {
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
+ ""authed"": ""1"",
+ ""bike"": ""FR1538"",
+ ""station"": ""FR105"",
+ ""description"": ""Contributor-bike Rainer"",
+ ""Ilockit_ID"": ""ISHAREIT-2200538"",
+ ""bike_group"": [
+ ""FR300103""
+ ],
+ ""state"": ""available"",
+ ""tariff_description"": {
+ ""max_eur_per_day"": ""10.00"",
+ ""eur_per_hour"": ""3.00"",
+ ""number"": ""5494"",
+ ""1538"": {
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB).""
+ },
+ ""free_hours"": ""0.50"",
+ ""name"": ""Tester Basic""
+ },
+ ""gps"": {
+ ""latitude"": ""47.9275957"",
+ ""longitude"": ""7.973976""
+ },
+ ""lock_state"": ""locked"",
+ ""system"": ""Ilockit"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-db0319a2555b""
+ },
+ ""FR1001"": {
+ ""bike_group"": [
+ ""FR300101""
+ ],
+ ""station"": ""FR101"",
+ ""description"": ""Lastenrad"",
+ ""Ilockit_ID"": ""ISHAREIT-2200536"",
+ ""authed"": ""1"",
+ ""bike"": ""FR1001"",
+ ""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
+ ""lock_state"": ""locked"",
+ ""gps"": {
+ ""latitude"": ""47.9765091"",
+ ""longitude"": ""7.8255631""
+ },
+ ""system"": ""Ilockit"",
+ ""Ilockit_GUID"": ""00000000-0000-0000-0000-caa87760e53e"",
+ ""state"": ""available"",
+ ""tariff_description"": {
+ ""free_hours"": ""0.50"",
+ ""name"": ""Vauban Basic"",
+ ""eur_per_hour"": ""2.00"",
+ ""number"": ""5491"",
+ ""max_eur_per_day"": ""10.00"",
+ ""1001"": {
+ ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB).""
+ }
+ }
+ }
+ },
+ ""user_group"": [
+ ""FR300103"",
+ ""FR300101""
+ ],
+ ""apiserver"": ""https://shareeapp-fr01.copri.eu"",
+ ""user_tour"": [],
+ ""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"",
+ ""copri_version"": ""4.1.8.21"",
+ ""response_state"": ""OK, nothing todo"",
+ ""new_authcoo"": ""0"",
+ ""bike_info_html"": ""site/bike_info.html"",
+ ""debuglevel"": ""1"",
+ ""uri_primary"": ""https://shareeapp-primary.copri.eu""
+ }
+ }";
+ }
+}