aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs
diff options
context:
space:
mode:
authorMirta <mirta@twine-s.com>2020-11-23 16:13:53 +0200
committerMirta <mirta@twine-s.com>2020-11-23 16:13:53 +0200
commit91c007adced573e09b77ab4be4a5aba623a816cc (patch)
tree250221fc2def7d59f1393be8394f766faf576656 /Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs
parent4e9af2b852eb3b9eecfa09e9bc76869558e183cb (diff)
parent50a3c0b857b4aa88a9e3970d69256f12b5b24eb8 (diff)
downloadTango-91c007adced573e09b77ab4be4a5aba623a816cc.tar.gz
Tango-91c007adced573e09b77ab4be4a5aba623a816cc.zip
Merge branch 'master' of https://twinetfs.visualstudio.com/Tango/_git/Tango
Diffstat (limited to 'Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs')
-rw-r--r--Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs331
1 files changed, 331 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs
new file mode 100644
index 000000000..383a59850
--- /dev/null
+++ b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs
@@ -0,0 +1,331 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Security.Authentication;
+using System.Web.Http;
+using Tango.BL.Builders;
+using Tango.BL.Entities;
+using Tango.BL.Enumerations;
+using Tango.Core.Cryptography;
+using Tango.DataStore;
+using Tango.DataStore.EF;
+using Tango.DataStore.Web;
+using Tango.MachineService.Filters;
+using Tango.Web.Controllers;
+using Tango.Web.Helpers;
+using Tango.Web.Security;
+using static Tango.MachineService.Controllers.DataStoreController;
+
+namespace Tango.MachineService.Controllers
+{
+ public class DataStoreController : TangoController<TokenObject>
+ {
+ public class TokenObject
+ {
+ public String UserGuid { get; set; }
+ public List<Permissions> Permissions { get; set; }
+
+ public TokenObject()
+ {
+ Permissions = new List<Permissions>();
+ }
+ }
+
+ private IDataStoreManager _manager;
+
+ public DataStoreController()
+ {
+ _manager = new EFDataStoreManager();
+ }
+
+ [HttpPost]
+ public LoginResponse Login(LoginRequest request)
+ {
+ User user = null;
+
+ IHashGenerator hash = new BasicHashGenerator();
+ var password = hash.Encrypt(request.Password);
+
+ using (var db = ObservablesContextHelper.CreateContext())
+ {
+ user = new UserBuilder(db).Set(x => x.Email.ToLower() == request.Email.ToLower() && x.Password == password).WithRolesAndPermissions().WithDeleted().Build();
+
+ if (user == null)
+ {
+ throw new AuthenticationException("Invalid email or password.");
+ }
+
+ if (user.Deleted)
+ {
+ throw new AuthenticationException("Your account has been disabled. Please contact your administrator.");
+ }
+
+ if (!user.HasPermission(Permissions.DataStoreRead))
+ {
+ throw new AuthenticationException("You are not authorized to access the data store.");
+ }
+
+ var token = WebToken<TokenObject>.CreateNew(MachineServiceConfig.JWT_TOKEN_SECRET, new TokenObject()
+ {
+ UserGuid = user.Guid,
+ Permissions = user.Permissions.Select(x => (Permissions)x.Code).ToList()
+ }, DateTime.UtcNow.AddDays(1));
+
+ return new LoginResponse()
+ {
+ Token = token.AccessToken,
+ ExpirationUTC = token.Expiration.Value,
+ };
+ }
+ }
+
+ [JwtWebApiTokenFilter]
+ public List<DataStoreWebItem> Get(String sn = null, String collection = null, String key = null)
+ {
+ try
+ {
+ if (!RequestToken.Object.Permissions.Contains(Permissions.DataStoreRead))
+ {
+ throw CreateHttpException(new AuthenticationException("The current user was not authorized to read from the data store."), HttpStatusCode.Unauthorized);
+ }
+
+ if (key != null && collection == null)
+ {
+ throw CreateHttpException(new ArgumentException(), HttpStatusCode.BadRequest, "When specifying a key, collection must be specified.");
+ }
+
+ ValidateCollectionAndKey(collection, key);
+
+ using (var db = ObservablesContextHelper.CreateContext())
+ {
+ if (sn != null)
+ {
+ var machineGuid = db.Machines.Where(x => x.SerialNumber == sn).Select(x => x.Guid).FirstOrDefault();
+
+ if (machineGuid == null)
+ {
+ throw CreateHttpException(new KeyNotFoundException(), HttpStatusCode.NotFound, "The specified machine serial number could not be found.");
+ }
+
+ var localItems = db.DataStoreItems.Where(x => !x.IsDeleted).Where(x => x.MachineGuid == machineGuid && (collection == null || x.CollectionName == collection) && (key == null || x.Key == key)).ToList();
+ var globalItems = db.GlobalDataStoreItems.Where(x => (collection == null || x.CollectionName == collection) && (key == null || x.Key == key)).ToList();
+
+ if (localItems.Count == 0 && globalItems.Count == 0 && key != null)
+ {
+ throw CreateHttpException(new KeyNotFoundException(), HttpStatusCode.NotFound, "The specified key was not found on the data store.");
+ }
+
+ List<DataStoreWebItem> finalList = new List<DataStoreWebItem>();
+
+ foreach (var localItem in localItems)
+ {
+ var globalItem = globalItems.FirstOrDefault(x => x.CollectionName == localItem.CollectionName && x.Key == localItem.Key);
+ finalList.Add(localItem.ToWebItem(globalItem));
+ globalItems.Remove(globalItem);
+ }
+
+ finalList.AddRange(globalItems.Select(x => x.ToWebItem()));
+
+ return finalList;
+ }
+ else
+ {
+ var globalItems = db.GlobalDataStoreItems.Where(x => (collection == null || x.CollectionName == collection) && (key == null || x.Key == key)).ToList();
+
+ var finalList = globalItems.Select(x => x.ToWebItem()).ToList();
+
+ return finalList;
+ }
+ }
+ }
+ catch (HttpResponseException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw CreateHttpException(ex, HttpStatusCode.InternalServerError);
+ }
+ }
+
+ [JwtWebApiTokenFilter]
+ public void Put([FromBody]DataStoreWebPutItem item)
+ {
+ try
+ {
+ if (!RequestToken.Object.Permissions.Contains(Permissions.DataStoreWrite))
+ {
+ throw CreateHttpException(new AuthenticationException("The current user was not authorized to write to the data store."), HttpStatusCode.Unauthorized);
+ }
+
+ if (item.Collection == null || item.Key == null)
+ {
+ throw CreateHttpException(new AuthenticationException("Collection and key must be specified."), HttpStatusCode.BadRequest);
+ }
+
+ ValidateCollectionAndKey(item.Collection, item.Key);
+
+ using (var db = ObservablesContextHelper.CreateContext())
+ {
+ if (item.MachineSerialNumber != null)
+ {
+ var machineGuid = db.Machines.Where(x => x.SerialNumber == item.MachineSerialNumber).Select(x => x.Guid).FirstOrDefault();
+
+ if (machineGuid == null)
+ {
+ throw CreateHttpException(new KeyNotFoundException("The specified machine serial number could not be found."), HttpStatusCode.NotFound);
+ }
+
+ DataStoreItem dbItem = db.DataStoreItems.FirstOrDefault(x => x.CollectionName == item.Collection && x.Key == item.Key);
+
+ if (dbItem == null)
+ {
+ if (!RequestToken.Object.Permissions.Contains(Permissions.DataStoreCreate))
+ {
+ throw CreateHttpException(new AuthenticationException("The current user was not authorized to create new items on the data store."), HttpStatusCode.Unauthorized);
+ }
+
+ dbItem = new DataStoreItem();
+ dbItem.Key = item.Key;
+ dbItem.CollectionName = item.Collection;
+ dbItem.MachineGuid = machineGuid;
+ db.DataStoreItems.Add(dbItem);
+ }
+
+ dbItem.DataType = (int)item.DataType;
+ dbItem.IsDeleted = false;
+ dbItem.IsSynchronized = false;
+ dbItem.LastUpdated = DateTime.UtcNow;
+ dbItem.Value = EFDataStoreHelper.CreateBytes(item.DataType, DataStoreHelper.ParseDataStoreValue(item.DataType, item.Value.ToStringSafe(), item.ProtoMessageType));
+ }
+ else
+ {
+ if (!RequestToken.Object.Permissions.Contains(Permissions.DataStoreCreateWriteGlobal))
+ {
+ throw CreateHttpException(new AuthenticationException("The current user was not authorized to write to the global data store."), HttpStatusCode.Unauthorized);
+ }
+
+ GlobalDataStoreItem dbItem = db.GlobalDataStoreItems.FirstOrDefault(x => x.CollectionName == item.Collection && x.Key == item.Key);
+
+ if (dbItem == null)
+ {
+ if (!RequestToken.Object.Permissions.Contains(Permissions.DataStoreCreate))
+ {
+ throw CreateHttpException(new AuthenticationException("The current user was not authorized to create new items on the data store."), HttpStatusCode.Unauthorized);
+ }
+
+ dbItem = new GlobalDataStoreItem();
+ dbItem.Key = item.Key;
+ dbItem.CollectionName = item.Collection;
+ db.GlobalDataStoreItems.Add(dbItem);
+ }
+
+ dbItem.DataType = (int)item.DataType;
+ dbItem.LastUpdated = DateTime.UtcNow;
+ dbItem.Value = EFDataStoreHelper.CreateBytes(item.DataType, DataStoreHelper.ParseDataStoreValue(item.DataType, item.Value.ToStringSafe(), item.ProtoMessageType));
+ }
+
+ db.SaveChanges();
+ }
+ }
+ catch (HttpResponseException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw CreateHttpException(ex, HttpStatusCode.InternalServerError);
+ }
+ }
+
+ private HttpResponseException CreateHttpException(Exception ex, HttpStatusCode code, String message = null)
+ {
+ return new HttpResponseException(new HttpResponseMessage(code)
+ {
+ Content = new StringContent(message != null ? message : ex.Message),
+ ReasonPhrase = ex.FlattenMessage()
+ });
+ }
+
+ private void ValidateCollectionAndKey(String collection = null, String key = null)
+ {
+ if (collection != null)
+ {
+ if (!DataStoreHelper.ValidateCollectionOrKeyName(collection))
+ {
+ throw new ArgumentException("Collection name contains invalid characters.");
+ }
+ }
+
+ if (key != null)
+ {
+ if (!DataStoreHelper.ValidateCollectionOrKeyName(key))
+ {
+ throw new ArgumentException("Item key contains invalid characters.");
+ }
+ }
+ }
+
+ }
+
+ #region Extension Methods
+
+ public static class IDataStoreExtensions
+ {
+ public static DataStoreWebItem ToWebItem(this DataStoreItem item, GlobalDataStoreItem globalItem = null)
+ {
+ IDataStoreItem dsItem = item.ToDataStoreItem();
+ DataStoreWebItem webItem = new DataStoreWebItem();
+ webItem.Collection = item.CollectionName;
+ webItem.Type = globalItem != null ? DataStoreWebItemType.Overrides : DataStoreWebItemType.Local;
+ webItem.DataType = dsItem.Type;
+ webItem.Date = dsItem.Date;
+ webItem.Key = dsItem.Key;
+ webItem.LocalValue = dsItem.Value;
+
+ if (webItem.LocalValue is DataStoreProtoObject protoObject)
+ {
+ webItem.LocalValue = protoObject.Message;
+ webItem.ProtoMessageType = protoObject.MessageType;
+ }
+
+ if (globalItem != null)
+ {
+ var dsGlobalItem = globalItem.ToDataStoreItem();
+
+ webItem.GlobalValue = dsGlobalItem.Value;
+
+ if (webItem.GlobalValue is DataStoreProtoObject protoObjectGlobal)
+ {
+ webItem.GlobalValue = protoObjectGlobal.Message;
+ webItem.ProtoMessageType = protoObjectGlobal.MessageType;
+ }
+ }
+
+ return webItem;
+ }
+
+ public static DataStoreWebItem ToWebItem(this GlobalDataStoreItem item)
+ {
+ IDataStoreItem dsItem = item.ToDataStoreItem();
+ DataStoreWebItem webItem = new DataStoreWebItem();
+ webItem.Collection = item.CollectionName;
+ webItem.Type = DataStoreWebItemType.Global;
+ webItem.DataType = dsItem.Type;
+ webItem.Date = dsItem.Date;
+ webItem.Key = dsItem.Key;
+ webItem.GlobalValue = dsItem.Value;
+
+ if (webItem.GlobalValue is DataStoreProtoObject protoObject)
+ {
+ webItem.GlobalValue = protoObject.Message;
+ webItem.ProtoMessageType = protoObject.MessageType;
+ }
+
+ return webItem;
+ }
+ }
+ #endregion
+}