Added Update client feature. localSettings updated.

This commit is contained in:
Andrey Shabarshov 2022-02-08 13:02:50 +00:00
parent edfdfacb2d
commit ad183ea33f
9 changed files with 159 additions and 29 deletions

View File

@ -3,7 +3,7 @@
"defaultVariables": null, "defaultVariables": null,
"documentGenerator": { "documentGenerator": {
"fromDocument": { "fromDocument": {
"json": "{\r\n \"openapi\": \"3.0.1\",\r\n \"info\": {\r\n \"title\": \"QRBee.Api\",\r\n \"version\": \"1.0\"\r\n },\r\n \"paths\": {\r\n \"/api/QRBee/Register\": {\r\n \"post\": {\r\n \"tags\": [\r\n \"QRBee\"\r\n ],\r\n \"requestBody\": {\r\n \"content\": {\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n },\r\n \"application/*+json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n }\r\n }\r\n },\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationResponse\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationResponse\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationResponse\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"components\": {\r\n \"schemas\": {\r\n \"RegistrationRequest\": {\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"name\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"email\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"dateOfBirth\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"certificateRequest\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"registerAsMerchant\": {\r\n \"type\": \"boolean\"\r\n }\r\n },\r\n \"additionalProperties\": false\r\n },\r\n \"RegistrationResponse\": {\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"clientId\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"certificate\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n }\r\n },\r\n \"additionalProperties\": false\r\n }\r\n }\r\n }\r\n}", "json": "{\r\n \"openapi\": \"3.0.1\",\r\n \"info\": {\r\n \"title\": \"QRBee.Api\",\r\n \"version\": \"1.0\"\r\n },\r\n \"paths\": {\r\n \"/api/QRBee/Register\": {\r\n \"post\": {\r\n \"tags\": [\r\n \"QRBee\"\r\n ],\r\n \"requestBody\": {\r\n \"content\": {\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n },\r\n \"application/*+json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n }\r\n }\r\n },\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\",\r\n \"content\": {\r\n \"text/plain\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationResponse\"\r\n }\r\n },\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationResponse\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationResponse\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"/api/QRBee/Update/{clientId}\": {\r\n \"patch\": {\r\n \"tags\": [\r\n \"QRBee\"\r\n ],\r\n \"parameters\": [\r\n {\r\n \"name\": \"clientId\",\r\n \"in\": \"path\",\r\n \"required\": true,\r\n \"schema\": {\r\n \"type\": \"string\"\r\n }\r\n }\r\n ],\r\n \"requestBody\": {\r\n \"content\": {\r\n \"application/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n },\r\n \"text/json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n },\r\n \"application/*+json\": {\r\n \"schema\": {\r\n \"$ref\": \"#/components/schemas/RegistrationRequest\"\r\n }\r\n }\r\n }\r\n },\r\n \"responses\": {\r\n \"200\": {\r\n \"description\": \"Success\"\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"components\": {\r\n \"schemas\": {\r\n \"RegistrationRequest\": {\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"name\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"email\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"dateOfBirth\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"certificateRequest\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"registerAsMerchant\": {\r\n \"type\": \"boolean\"\r\n }\r\n },\r\n \"additionalProperties\": false\r\n },\r\n \"RegistrationResponse\": {\r\n \"type\": \"object\",\r\n \"properties\": {\r\n \"clientId\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n },\r\n \"certificate\": {\r\n \"type\": \"string\",\r\n \"nullable\": true\r\n }\r\n },\r\n \"additionalProperties\": false\r\n }\r\n }\r\n }\r\n}",
"url": "http://redocly.github.io/redoc/openapi.yaml", "url": "http://redocly.github.io/redoc/openapi.yaml",
"output": null, "output": null,
"newLineBehavior": "Auto" "newLineBehavior": "Auto"

View File

@ -130,6 +130,81 @@ namespace QRBee.Core.Client
} }
} }
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task UpdateAsync(string clientId, RegistrationRequest body)
{
return UpdateAsync(clientId, body, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task UpdateAsync(string clientId, RegistrationRequest body, System.Threading.CancellationToken cancellationToken)
{
if (clientId == null)
throw new System.ArgumentNullException("clientId");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/QRBee/Update/{clientId}");
urlBuilder_.Replace("{clientId}", System.Uri.EscapeDataString(ConvertToString(clientId, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value));
content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("PATCH");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
protected struct ObjectResponseResult<T> protected struct ObjectResponseResult<T>
{ {
public ObjectResponseResult(T responseObject, string responseText) public ObjectResponseResult(T responseObject, string responseText)

View File

@ -8,8 +8,9 @@ namespace QRBee.Services
public class Settings public class Settings
{ {
//TODO add ClientId //TODO add ClientId
public string ClientId { get; set; }
public string PIN { get; set; } public string PIN { get; set; }
public bool IsRegistered { get; set; } public bool IsRegistered => !string.IsNullOrWhiteSpace(ClientId);
public string Name { get; set; } public string Name { get; set; }
public string Email { get; set; } public string Email { get; set; }

View File

@ -102,34 +102,50 @@ namespace QRBee.ViewModels
try try
{ {
//TODO Check if ClientId already in LocalSettings. If Yes update data in database //TODO Check if ClientId already in LocalSettings. If Yes update data in database
var settings = localSettings.LoadSettings();
//save local settings //save local settings
var settings = new Settings settings.CardHolderName = CardHolderName;
{ settings.CardNumber = CardNumber;
CardHolderName = CardHolderName, settings.CVC = CVC;
CardNumber = CardNumber, settings.DateOfBirth = DateOfBirth;
CVC = CVC, settings.Email = Email;
DateOfBirth = DateOfBirth, settings.ExpirationDate = ExpirationDate;
Email = Email, settings.IssueNo = IssueNo;
ExpirationDate = ExpirationDate, settings.ValidFrom = ValidFrom;
IsRegistered = true, settings.Name = Name;
IssueNo = IssueNo, settings.PIN = Pin;
ValidFrom = ValidFrom,
Name = Name,
PIN = Pin
};
await localSettings.SaveSettings(settings); await localSettings.SaveSettings(settings);
await service.RegisterAsync(new RegistrationRequest var request = new RegistrationRequest
{ {
DateOfBirth = DateOfBirth.ToString("yyyy-MM-dd"), DateOfBirth = DateOfBirth.ToString("yyyy-MM-dd"),
Email = Email, Email = Email,
Name = Name, Name = Name,
RegisterAsMerchant = false RegisterAsMerchant = false
}); };
if (!settings.IsRegistered)
{
var response = await service.RegisterAsync(request);
// Save ClientId to LocalSettings
settings = localSettings.LoadSettings();
settings.ClientId = response.ClientId;
await localSettings.SaveSettings(settings);
var page = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault(); var page = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
await page.DisplayAlert("Success", "You have been registered successfully", "Ok"); await page.DisplayAlert("Success", "You have been registered successfully", "Ok");
}
else
{
await service.UpdateAsync(settings.ClientId, request);
var page = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
await page.DisplayAlert("Success", "Your data has been updated successfully", "Ok");
}
await Shell.Current.GoToAsync($"//{nameof(MainPage)}"); await Shell.Current.GoToAsync($"//{nameof(MainPage)}");
} }

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
using QRBee.Api.Services; using QRBee.Api.Services;
using QRBee.Core; using QRBee.Core;
using QRBee.Core.Data; using QRBee.Core.Data;
@ -27,5 +28,11 @@ namespace QRBee.Api.Controllers
return _service.Register(value); return _service.Register(value);
} }
[HttpPatch("Update/{clientId}")]
public Task Update([FromRoute] string clientId, [FromBody] RegistrationRequest value)
{
_logger.LogInformation($"Trying to update user {value.Name}");
return _service.Update(clientId,value);
}
} }
} }

View File

@ -19,5 +19,7 @@
/// <returns>User information</returns> /// <returns>User information</returns>
Task<UserInfo> GetUserInfo(string email); Task<UserInfo> GetUserInfo(string email);
Task UpdateUser(UserInfo info);
} }
} }

View File

@ -1,5 +1,6 @@
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using MongoDB.Driver; using MongoDB.Driver;
using QRBee.Api.Controllers;
namespace QRBee.Api.Services.Database namespace QRBee.Api.Services.Database
{ {
@ -7,12 +8,14 @@ namespace QRBee.Api.Services.Database
{ {
private readonly IMongoDatabase _database; private readonly IMongoDatabase _database;
private readonly ILogger<Storage> _logger;
public Storage(IMongoClient client, IOptions<DatabaseSettings> settings) public Storage(IMongoClient client, IOptions<DatabaseSettings> settings, ILogger<Storage> logger)
{ {
var name = settings.Value.DatabaseName; var name = settings.Value.DatabaseName;
_database = client.GetDatabase(name); _database = client.GetDatabase(name);
_logger = logger;
} }
public async Task<string> PutUserInfo(UserInfo info) public async Task<string> PutUserInfo(UserInfo info)
@ -27,13 +30,20 @@ namespace QRBee.Api.Services.Database
if (user == null) if (user == null)
{ {
await collection.InsertOneAsync(info); await collection.InsertOneAsync(info);
_logger.LogInformation($"Inserted new user with Email: {info.Email} and ID: {info.ClientId}");
return info.ClientId ?? throw new ApplicationException($"ClientId is null while adding user {info.Email}"); return info.ClientId ?? throw new ApplicationException($"ClientId is null while adding user {info.Email}");
} }
// Update command will not be used due to not knowing if the user is legitimate
_logger.LogInformation($"Found user with Email: {info.Email} and ID: {info.ClientId}");
return user.ClientId ?? throw new ApplicationException($"ClientId is null while adding user {info.Email}"); return user.ClientId ?? throw new ApplicationException($"ClientId is null while adding user {info.Email}");
} }
/// <summary>
/// Check if user already exists in database
/// </summary>
/// <param name="email">Parameter by which to find UserInfo</param>
/// <returns>null if user doesn't exist or UserInfo</returns>
internal async Task<UserInfo?> TryGetUserInfo(string email) internal async Task<UserInfo?> TryGetUserInfo(string email)
{ {
var collection = _database.GetCollection<UserInfo>("Users"); var collection = _database.GetCollection<UserInfo>("Users");
@ -52,5 +62,11 @@ namespace QRBee.Api.Services.Database
return user ?? throw new ApplicationException($"User {email} not found."); return user ?? throw new ApplicationException($"User {email} not found.");
} }
public async Task UpdateUser(UserInfo info)
{
var collection = _database.GetCollection<UserInfo>("Users");
await collection.ReplaceOneAsync($"{{ _id: \"{info.Id}\" }}",info, new ReplaceOptions(){IsUpsert = false});
}
} }
} }

View File

@ -16,5 +16,12 @@ namespace QRBee.Api.Services
/// <returns>Registration response</returns> /// <returns>Registration response</returns>
Task<RegistrationResponse> Register(RegistrationRequest value); Task<RegistrationResponse> Register(RegistrationRequest value);
/// <summary>
/// Handles Update request
/// </summary>
/// <param name="clientId"></param>
/// <param name="value">Update request</param>
Task Update(string clientId, RegistrationRequest value);
} }
} }

View File

@ -26,13 +26,19 @@ namespace QRBee.Api.Services
Validate(request); Validate(request);
var info = Convert(request); var info = Convert(request);
//TODO Check that user doesn't exist(name,surname,dateOfBirth or Telephone number(get from Android))
var clientId = await _storage.PutUserInfo(info); var clientId = await _storage.PutUserInfo(info);
return new RegistrationResponse{ClientId = clientId}; return new RegistrationResponse{ClientId = clientId};
} }
//TODO Write an UpdateUser command
public Task Update(string clientId, RegistrationRequest request)
{
Validate(request);
var info = Convert(request);
return _storage.UpdateUser(info);
}
private static void Validate(RegistrationRequest request) private static void Validate(RegistrationRequest request)
{ {
if (request == null) if (request == null)
@ -66,7 +72,7 @@ namespace QRBee.Api.Services
} }
private UserInfo Convert(RegistrationRequest request) private static UserInfo Convert(RegistrationRequest request)
{ {
return new UserInfo(request.Name, request.Email, request.DateOfBirth); return new UserInfo(request.Name, request.Email, request.DateOfBirth);
} }