diff options
| author | Mirta <mirta@twine-s.com> | 2020-11-23 16:13:53 +0200 |
|---|---|---|
| committer | Mirta <mirta@twine-s.com> | 2020-11-23 16:13:53 +0200 |
| commit | 91c007adced573e09b77ab4be4a5aba623a816cc (patch) | |
| tree | 250221fc2def7d59f1393be8394f766faf576656 /Software/Visual_Studio/Web/Tango.MachineService/Controllers | |
| parent | 4e9af2b852eb3b9eecfa09e9bc76869558e183cb (diff) | |
| parent | 50a3c0b857b4aa88a9e3970d69256f12b5b24eb8 (diff) | |
| download | Tango-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')
| -rw-r--r-- | Software/Visual_Studio/Web/Tango.MachineService/Controllers/DataStoreController.cs | 331 | ||||
| -rw-r--r-- | Software/Visual_Studio/Web/Tango.MachineService/Controllers/PPCController.cs | 19 |
2 files changed, 345 insertions, 5 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 +} diff --git a/Software/Visual_Studio/Web/Tango.MachineService/Controllers/PPCController.cs b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/PPCController.cs index fbc4f8a0a..161caaf23 100644 --- a/Software/Visual_Studio/Web/Tango.MachineService/Controllers/PPCController.cs +++ b/Software/Visual_Studio/Web/Tango.MachineService/Controllers/PPCController.cs @@ -105,7 +105,7 @@ namespace Tango.MachineService.Controllers var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == machine.MachineVersionGuid); - var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); + var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid && !x.Disabled).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); response.Version = latest_machine_version.Version; response.FirmwareVersion = latest_machine_version.FirmwareVersion; @@ -186,6 +186,15 @@ namespace Tango.MachineService.Controllers LogManager.Log(ex, $"Error resetting synchronized job runs for machine '{machine.SerialNumber}'."); } + try + { + b.DataStoreItems.Where(x => x.MachineGuid == machine.Guid).Update(x => new DataStoreItem() { IsSynchronized = false }); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error resetting synchronized data store items for machine '{machine.SerialNumber}'."); + } + //Reset Events. //b.MachinesEvents.Where(x => x.MachineGuid == machine.Guid).Update(x => new MachinesEvent() { IsSynchronized = false }); //Reset Jobs. @@ -218,7 +227,7 @@ namespace Tango.MachineService.Controllers var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == machine.MachineVersionGuid); - var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); + var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid && !x.Disabled).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); response.Version = latest_machine_version.Version; response.FirmwareVersion = latest_machine_version.FirmwareVersion; @@ -337,9 +346,9 @@ namespace Tango.MachineService.Controllers { var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == machine.MachineVersionGuid); - var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); + var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid && !x.Disabled).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); - if (Version.Parse(latest_machine_version.Version) != Version.Parse(request.Version)) + if (Version.Parse(latest_machine_version.Version) > Version.Parse(request.Version)) { response.IsUpdateAvailable = true; } @@ -755,7 +764,7 @@ namespace Tango.MachineService.Controllers //Send DataStore Items if (request.RequestDataStoreItems) { - var dataStoreItems = db.DataStoreItems.Where(x => x.MachineGuid == machine.Guid && !x.IsSynchronized).Take(request.MaxDataStoreItems).OrderByDescending(x => x.LastUpdated).ToList(); + var dataStoreItems = db.DataStoreItems.Where(x => x.MachineGuid == machine.Guid && !x.IsSynchronized & !x.IsDeleted).Take(request.MaxDataStoreItems).OrderByDescending(x => x.LastUpdated).ToList(); foreach (var item in dataStoreItems) { |
