using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Web.Http;
using Tango.BL;
using Tango.BL.Builders;
using Tango.BL.Entities;
using Tango.BL.Enumerations;
using Tango.Core;
using Tango.Core.DB;
using Tango.Logging;
using Tango.MachineService.Models;
using Tango.PPC.Common.Web;
using Tango.Web.Controllers;
using Tango.Web.Helpers;
using Tango.Web.SMO;
using Tango.Web.Storage;
using System.Data.Entity;
using Tango.Web.Security;
using Tango.Web.ActiveDirectory;
using Tango.Core.Cryptography;
using Tango.MachineService.Filters;
using Tango.BL.DTO;
using Z.EntityFramework.Plus;
namespace Tango.MachineService.Controllers
{
public class PPCController : TangoController<PPCController.TokenObject>
{
private static List<PPCPendingUpload> _pendingUploads;
private static List<PPCPendingUpdate> _pendingUpdates;
private ActiveDirectoryManager _ad_manager;
public const int SQL_TEMP_CREDENTIALS_EXP_MINUTS = 20;
public class TokenObject
{
public LoginMode Mode { get; set; }
public String UserGuid { get; set; }
public String MachineGuid { get; set; }
}
#region Constructors
static PPCController()
{
_pendingUploads = new List<PPCPendingUpload>();
_pendingUpdates = new List<PPCPendingUpdate>();
}
public PPCController()
{
_ad_manager = new ActiveDirectoryManager();
}
#endregion
#region Setup & Update
[HttpPost]
[JwtTokenFilter]
public MachineSetupResponse MachineSetup(MachineSetupRequest request)
{
MachineSetupResponse response = new MachineSetupResponse();
response.NotifyCompletedToken = Guid.NewGuid().ToString();
LogManager.Log("Setup request received: " + request.ToString());
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
String machine_guid = RequestToken.Object.MachineGuid;
var machine = db.Machines.Include(x => x.Organization).SingleOrDefault(x => x.Guid == machine_guid);
if (machine == null)
{
throw new AuthenticationException("The specified serial number could not be found.");
}
if (machine.SetupActivation && String.IsNullOrWhiteSpace(machine.OsKey))
{
throw new InvalidDataException("The specified machine is configured to perform an OS activation but is not associated with an OS activation key.");
}
if (String.IsNullOrWhiteSpace(request.DeviceID))
{
throw new InvalidDataException("Device id not set.");
}
if (String.IsNullOrWhiteSpace(request.DeviceName))
{
throw new InvalidDataException("Device name not set.");
}
if (machine.IsDeviceRegistered && machine.DeviceId != request.DeviceID)
{
throw new InvalidDataException("The specified machine is already registered and device id is invalid.");
}
machine.DeviceName = request.DeviceName;
machine.DeviceId = request.DeviceID;
machine.IsDeviceRegistered = true;
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();
response.Version = latest_machine_version.Version;
response.FirmwareVersion = latest_machine_version.FirmwareVersion;
var manager = new BlobStorageManager();
var container = manager.GetContainer(MachineServiceConfig.TANGO_VERSIONS_CONTAINER);
var blob = container.GetBlockBlobReference(latest_machine_version.BlobName);
response.BlobAddress = blob.GenerateReadSignature(TimeSpan.FromMinutes(60));
if (!String.IsNullOrWhiteSpace(MachineServiceConfig.CDN_ENDPOINT))
{
response.CdnAddress = MachineServiceConfig.CDN_ENDPOINT + blob.Uri.AbsolutePath;
}
DbCredentials credentials = new DbCredentials();
using (SmoManager smo = new SmoManager())
{
credentials = smo.CreateRandomLoginAndUser();
Task.Delay(TimeSpan.FromMinutes(SQL_TEMP_CREDENTIALS_EXP_MINUTS)).ContinueWith((x) =>
{
using (SmoManager m = new SmoManager())
{
m.DeleteLoginAndUser(credentials.UserName);
}
});
}
response.DataSource = new DataSource()
{
Address = MachineServiceConfig.DB_ADDRESS,
Catalog = MachineServiceConfig.DB_CATALOG,
UserName = credentials.UserName,
Password = credentials.Password,
IntegratedSecurity = false,
Type = DataSourceType.SQLServer,
};
response.OSKey = machine.OsKey;
response.SetupActivation = machine.SetupActivation;
response.SetupRemoteAssistance = machine.SetupRemoteAssistance;
response.SetupUWF = machine.SetupUwf;
response.SetupFirmware = machine.SetupFirmware;
response.IsDemo = machine.IsDemo;
response.Organization = machine.Organization.Name;
TangoUpdate tangoUpdate = new TangoUpdate();
tangoUpdate.ApplicationVersion = latest_machine_version.Version;
tangoUpdate.FirmwareVersion = latest_machine_version.FirmwareVersion;
tangoUpdate.MachineGuid = machine.Guid;
tangoUpdate.StartDate = DateTime.UtcNow;
tangoUpdate.UpdateStatus = TangoUpdateStatuses.SetupStarted;
db.TangoUpdates.Add(tangoUpdate);
machine.ProductionDate = DateTime.UtcNow;
db.SaveChanges();
_pendingUpdates.Add(new PPCPendingUpdate()
{
Token = response.NotifyCompletedToken,
TangoUpdateGuid = tangoUpdate.Guid,
});
Task.Factory.StartNew(() =>
{
using (ObservablesContext b = ObservablesContextHelper.CreateContext())
{
//Reset Job Runs.
try
{
b.JobRuns.Where(x => x.MachineGuid == machine.Guid && x.IsSynchronized).Update(x => new JobRun() { IsSynchronized = false });
}
catch (Exception ex)
{
LogManager.Log(ex, $"Error resetting synchronized job runs for machine '{machine.SerialNumber}'.");
}
//Reset Events.
//b.MachinesEvents.Where(x => x.MachineGuid == machine.Guid).Update(x => new MachinesEvent() { IsSynchronized = false });
//Reset Jobs.
//b.Jobs.Where(x => x.MachineGuid == machine.Guid).Update(x => new Job() { IsSynchronized = false });
}
});
}
return response;
}
[HttpPost]
[JwtTokenFilter]
public DownloadUpdateResponse MachineUpdate(DownloadUpdateRequest request)
{
DownloadUpdateResponse response = new DownloadUpdateResponse();
response.NotifyCompletedToken = Guid.NewGuid().ToString();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
db.Configuration.LazyLoadingEnabled = false;
String machine_guid = RequestToken.Object.MachineGuid;
var machine = db.Machines.SingleOrDefault(x => x.Guid == machine_guid);
if (machine == null)
{
throw new AuthenticationException("The specified serial number could not be found.");
}
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();
response.Version = latest_machine_version.Version;
response.FirmwareVersion = latest_machine_version.FirmwareVersion;
var manager = new BlobStorageManager();
var container = manager.GetContainer(MachineServiceConfig.TANGO_VERSIONS_CONTAINER);
var blob = container.GetBlockBlobReference(latest_machine_version.BlobName);
response.BlobAddress = blob.GenerateReadSignature(TimeSpan.FromMinutes(60));
if (!String.IsNullOrWhiteSpace(MachineServiceConfig.CDN_ENDPOINT))
{
response.CdnAddress = MachineServiceConfig.CDN_ENDPOINT + blob.Uri.AbsolutePath;
}
DbCredentials credentials = new DbCredentials();
using (SmoManager smo = new SmoManager())
{
credentials = smo.CreateRandomLoginAndUser();
Task.Delay(TimeSpan.FromMinutes(SQL_TEMP_CREDENTIALS_EXP_MINUTS)).ContinueWith((x) =>
{
using (SmoManager m = new SmoManager())
{
m.DeleteLoginAndUser(credentials.UserName);
}
});
}
response.DataSource = new DataSource()
{
Address = MachineServiceConfig.DB_ADDRESS,
Catalog = MachineServiceConfig.DB_CATALOG,
UserName = credentials.UserName,
Password = credentials.Password,
IntegratedSecurity = false,
Type = DataSourceType.SQLServer,
};
TangoUpdate tangoUpdate = new TangoUpdate();
tangoUpdate.ApplicationVersion = latest_machine_version.Version;
tangoUpdate.FirmwareVersion = latest_machine_version.FirmwareVersion;
tangoUpdate.MachineGuid = machine.Guid;
tangoUpdate.StartDate = DateTime.UtcNow;
tangoUpdate.UpdateStatus = TangoUpdateStatuses.UpdateStarted;
db.TangoUpdates.Add(tangoUpdate);
db.SaveChanges();
_pendingUpdates.Add(new PPCPendingUpdate()
{
Token = response.NotifyCompletedToken,
TangoUpdateGuid = tangoUpdate.Guid,
});
}
return response;
}
[HttpPost]
[JwtTokenFilter]
public MachineUpdateCompletedResponse NotifyUpdateCompleted(MachineUpdateCompletedRequest request)
{
var pendingUpdate = _pendingUpdates.SingleOrDefault(x => x.Token == request.Token);
if (pendingUpdate != null)
{
_pendingUpdates.Remove(pendingUpdate);
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
var tangoUpdate = db.TangoUpdates.SingleOrDefault(x => x.Guid == pendingUpdate.TangoUpdateGuid);
if (tangoUpdate != null)
{
tangoUpdate.LastUpdated = DateTime.UtcNow;
tangoUpdate.UpdateStatus = request.Status;
tangoUpdate.EndDate = DateTime.UtcNow;
tangoUpdate.FailedReason = request.FailedReason;
tangoUpdate.FailedLog = request.FailedLog;
if (request.ReportsAboutDbCheckNoDifferences)
{
db.TangoUpdates.Remove(tangoUpdate);
}
db.SaveChanges();
}
}
}
return new MachineUpdateCompletedResponse();
}
[HttpPost]
[JwtTokenFilter]
public CheckForUpdateResponse CheckForUpdates(CheckForUpdateRequest request)
{
CheckForUpdateResponse response = new CheckForUpdateResponse();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
String machine_guid = RequestToken.Object.MachineGuid;
var machine = db.Machines.SingleOrDefault(x => x.Guid == machine_guid);
if (machine == null)
{
throw new AuthenticationException("The specified serial number could not be found.");
}
response.SetupFirmware = machine.SetupFirmware;
response.SetupFPGA = machine.SetupFpga;
if (!machine.SuspendVersionUpdate)
{
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();
if (Version.Parse(latest_machine_version.Version) != Version.Parse(request.Version))
{
response.IsUpdateAvailable = true;
}
if (!machine.IsDemo && machine.SetupFirmware)
{
if (!String.IsNullOrWhiteSpace(request.FirmwareVersion))
{
if (Version.Parse(latest_machine_version.FirmwareVersion) > Version.Parse(request.FirmwareVersion))
{
response.IsUpdateAvailable = true;
}
}
}
response.Version = latest_machine_version.Version;
response.FirmwareVersion = latest_machine_version.FirmwareVersion;
//Compare database
var rmls = db.Rmls.Select(x => new { x.Guid, x.LastUpdated }).ToList();
var hardwareVersions = db.HardwareVersions.Select(x => new { x.Guid, x.LastUpdated }).ToList();
var catalogs = db.ColorCatalogs.Select(x => new { x.Guid, x.LastUpdated }).ToList();
var arr = request.UsedRmlsGuids.ToArray();
var existingRml = db.Rmls.Where(x => arr.Contains(x.Guid)).Select(x => x.Guid).Distinct().ToList();
response.UsedNotExistingRmlsGuids = arr.Where(x => !existingRml.Exists(y => y == x)).ToList();
bool hasDatabaseUpdates = false;
hasDatabaseUpdates = machine.LastUpdated > request.MachineLastUpdated;
if (!hasDatabaseUpdates)
{
hasDatabaseUpdates = rmls.Exists(x => request.Rmls.Exists(y => x.Guid == y.Guid && x.LastUpdated > y.LastUpdated) || !request.Rmls.Exists(y => x.Guid == y.Guid));
}
if (!hasDatabaseUpdates)
{
hasDatabaseUpdates = hardwareVersions.Exists(x => request.HardwareVersions.Exists(y => x.Guid == y.Guid && x.LastUpdated > y.LastUpdated) || !request.HardwareVersions.Exists(y => x.Guid == y.Guid));
}
if (!hasDatabaseUpdates)
{
hasDatabaseUpdates = catalogs.Exists(x => request.Catalogs.Exists(y => x.Guid == y.Guid && x.LastUpdated > y.LastUpdated) || !request.Catalogs.Exists(y => x.Guid == y.Guid));
}
if (hasDatabaseUpdates)
{
response.IsDatabaseUpdateAvailable = true;
response.UpdateDBResponse = UpdateDB(new UpdateDBRequest() { SerialNumber = request.SerialNumber });
}
//Compare database
if (machine.ForceVersionUpdate)
{
response.IsUpdateAvailable = true;
}
}
}
return response;
}
[HttpPost]
[JwtTokenFilter]
public UpdateDBResponse UpdateDB(UpdateDBRequest request)
{
UpdateDBResponse response = new UpdateDBResponse();
response.NotifyCompletedToken = Guid.NewGuid().ToString();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
String machine_guid = RequestToken.Object.MachineGuid;
var machine = db.Machines.SingleOrDefault(x => x.Guid == machine_guid);
if (machine == null)
{
throw new AuthenticationException("The specified serial number could not be found.");
}
response.PerformSchemaUpdate = machine.PerformSchemaUpdateOnDataUpdate;
DbCredentials credentials = new DbCredentials();
using (SmoManager manager = new SmoManager())
{
credentials = manager.CreateRandomLoginAndUser();
Task.Delay(TimeSpan.FromMinutes(SQL_TEMP_CREDENTIALS_EXP_MINUTS)).ContinueWith((x) =>
{
using (SmoManager m = new SmoManager())
{
m.DeleteLoginAndUser(credentials.UserName);
}
});
}
response.DataSource = new DataSource()
{
Address = MachineServiceConfig.DB_ADDRESS,
Catalog = MachineServiceConfig.DB_CATALOG,
UserName = credentials.UserName,
Password = credentials.Password,
IntegratedSecurity = false,
Type = DataSourceType.SQLServer,
};
TangoUpdate tangoUpdate = new TangoUpdate();
tangoUpdate.ApplicationVersion = request.ApplicationVersion;
tangoUpdate.FirmwareVersion = request.FirmwareVersion;
tangoUpdate.MachineGuid = machine.Guid;
tangoUpdate.StartDate = DateTime.UtcNow;
tangoUpdate.UpdateStatus = TangoUpdateStatuses.DatabaseStarted;
db.TangoUpdates.Add(tangoUpdate);
db.SaveChanges();
_pendingUpdates.Add(new PPCPendingUpdate()
{
Token = response.NotifyCompletedToken,
TangoUpdateGuid = tangoUpdate.Guid,
});
}
return response;
}
#endregion
#region Synchronization
[HttpPost]
[JwtTokenFilter]
public UploadMachineDataResponse UploadMachineData(UploadMachineDataRequest request)
{
UploadMachineDataResponse response = new UploadMachineDataResponse();
response.NotifyCompletedToken = Guid.NewGuid().ToString();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);
if (machine == null)
{
throw new AuthenticationException("The specified machine could not be found.");
}
TangoUpdate tangoUpdate = new TangoUpdate();
tangoUpdate.ApplicationVersion = request.ApplicationVersion;
tangoUpdate.FirmwareVersion = request.FirmwareVersion;
tangoUpdate.MachineGuid = machine.Guid;
tangoUpdate.StartDate = DateTime.UtcNow;
tangoUpdate.UpdateStatus = TangoUpdateStatuses.SynchronizationStarted;
db.TangoUpdates.Add(tangoUpdate);
db.SaveChanges();
_pendingUpdates.Add(new PPCPendingUpdate()
{
Token = response.NotifyCompletedToken,
TangoUpdateGuid = tangoUpdate.Guid,
});
}
User machineUser = null;
try
{
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);
if (machine == null)
{
throw new AuthenticationException("The specified machine could not be found.");
}
machineUser = db.Users.Include(x => x.Contact).SingleOrDefault(x => x.Contact.FirstName == machine.Name);
if (machineUser == null)
{
//No machine user then create one.
machineUser = new User();
machineUser.Email = machine.SerialNumber + "@twine-s.com";
machineUser.Password = machine.SerialNumber;
machineUser.OrganizationGuid = machine.OrganizationGuid;
machineUser.Contact = new Contact();
machineUser.Contact.Email = machineUser.Email;
machineUser.Contact.FirstName = machine.Name;
machineUser.Contact.LastName = machine.Name;
machineUser.Contact.FullName = machine.Name;
machineUser.Address = new Address();
db.Users.Add(machineUser);
db.SaveChanges();
}
}
//Insert/Replace Jobs.
foreach (var dto in request.Jobs)
{
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
try
{
var job = dto.ToObservable();
job.ID = 0;
job.UserGuid = machineUser.Guid;
job.CustomerGuid = null;
job.IsSynchronized = true;
var existingJob = db.Jobs.SingleOrDefault(x => x.Guid == job.Guid);
if (existingJob == null)
{
db.Jobs.Add(job);
db.SaveChanges();
}
else if (job.LastUpdated > existingJob.LastUpdated)
{
existingJob.Delete(db);
db.Jobs.Add(job);
db.SaveChanges();
}
}
catch (Exception ex)
{
response.FailedJobs.Add(new SynchronizationFailedEntity()
{
Guid = dto.Guid,
Reason = ex.FlattenMessage(),
});
}
}
}
//Insert JobRuns.
foreach (var dto in request.JobRuns)
{
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
try
{
var run = dto.ToObservable();
run.ID = 0;
run.UserGuid = machineUser.Guid;
run.IsSynchronized = true;
if (db.JobRuns.SingleOrDefault(x => x.Guid == run.Guid) == null)
{
db.JobRuns.Add(run);
db.SaveChanges();
}
}
catch (Exception ex)
{
response.FailedJobRuns.Add(new SynchronizationFailedEntity()
{
Guid = dto.Guid,
Reason = ex.FlattenMessage(),
});
}
}
}
//Insert MachineEvents.
foreach (var dto in request.MachineEvents)
{
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
try
{
var ev = dto.ToObservable();
ev.ID = 0;
ev.UserGuid = machineUser.Guid;
ev.IsSynchronized = true;
if (db.MachinesEvents.SingleOrDefault(x => x.Guid == ev.Guid) == null)
{
db.MachinesEvents.Add(ev);
db.SaveChanges();
}
}
catch (Exception ex)
{
response.FailedMachineEvents.Add(new SynchronizationFailedEntity()
{
Guid = dto.Guid,
Reason = ex.FlattenMessage(),
});
}
}
}
//Insert TangoUpdates.
foreach (var dto in request.OfflineUpdates)
{
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
try
{
var update = dto.ToObservable();
update.ID = 0;
update.IsSynchronized = true;
if (db.TangoUpdates.SingleOrDefault(x => x.Guid == update.Guid) == null)
{
db.TangoUpdates.Add(update);
db.SaveChanges();
}
}
catch (Exception ex)
{
response.FailedOfflineUpdates.Add(new SynchronizationFailedEntity()
{
Guid = dto.Guid,
Reason = ex.FlattenMessage(),
});
}
}
}
}
catch (Exception ex)
{
NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
{
Status = TangoUpdateStatuses.SynchronizationFailed,
FailedReason = ex.FlattenMessage(),
FailedLog = ex.FlattenException(),
Token = response.NotifyCompletedToken,
});
throw ex;
}
return response;
}
[HttpPost]
[JwtTokenFilter]
public DownloadMachineDataResponse DownloadMachineData(DownloadMachineDataRequest request)
{
DownloadMachineDataResponse response = new DownloadMachineDataResponse();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);
if (machine == null)
{
throw new AuthenticationException("The specified machine could not be found.");
}
//Send Jobs
if (request.RequestJobs)
{
var jobs = new JobsCollectionBuilder(db).Set(x => x.MachineGuid == machine.Guid && !x.IsSynchronized).WithSegments().WithBrushStops().Query(x => x.Take(request.MaxJobs).OrderByDescending(z => z.LastUpdated)).BuildList();
foreach (var job in jobs)
{
JobDTO dto = JobDTO.FromObservable(job);
response.Jobs.Add(dto);
}
}
//Send Job Runs
if (request.RequestJobRuns)
{
var jobRuns = db.JobRuns.Where(x => x.MachineGuid == machine.Guid && !x.IsSynchronized).Take(request.MaxJobRuns).OrderByDescending(x => x.LastUpdated).ToList();
foreach (var jobRun in jobRuns)
{
JobRunDTO dto = JobRunDTO.FromObservable(jobRun);
response.JobRuns.Add(dto);
}
}
//Send Machine Events
if (request.RequestMachineEvents)
{
var machineEvents = db.MachinesEvents.Where(x => x.MachineGuid == machine.Guid && !x.IsSynchronized).Take(request.MaxMachinesEvents).OrderByDescending(x => x.LastUpdated).ToList();
foreach (var machineEvent in machineEvents)
{
MachinesEventDTO dto = MachinesEventDTO.FromObservable(machineEvent);
response.MachineEvents.Add(dto);
}
}
}
return response;
}
[HttpPost]
[JwtTokenFilter]
public NotifyMachineDataDownloadCompletedResponse NotifyMachineDataDownloadCompleted(NotifyMachineDataDownloadCompletedRequest request)
{
var response = new NotifyMachineDataDownloadCompletedResponse();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);
if (machine == null)
{
throw new AuthenticationException("The specified machine could not be found.");
}
if (request.SynchronizedJobs.Count > 0)
{
db.Database.ExecuteSqlCommand($"UPDATE JOBS SET IS_SYNCHRONIZED = 1 WHERE GUID IN ({String.Join(",", request.SynchronizedJobs.Select(x => "'" + x + "'"))});");
}
if (request.SynchronizedJobRuns.Count > 0)
{
db.Database.ExecuteSqlCommand($"UPDATE JOB_RUNS SET IS_SYNCHRONIZED = 1 WHERE GUID IN ({String.Join(",", request.SynchronizedJobRuns.Select(x => "'" + x + "'"))});");
}
if (request.SynchronizedMachineEvents.Count > 0)
{
db.Database.ExecuteSqlCommand($"UPDATE MACHINES_EVENTS SET IS_SYNCHRONIZED = 1 WHERE GUID IN ({String.Join(",", request.SynchronizedMachineEvents.Select(x => "'" + x + "'"))});");
}
}
return response;
}
#endregion
#region Version Upload
[HttpPost]
public LatestVersionResponse GetLatestVersion(LatestVersionRequest request)
{
LatestVersionResponse response = new LatestVersionResponse();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
var versions = db.TangoVersions.Where(x => x.MachineVersionGuid == request.MachineVersionGuid).ToList();
if (versions.Count == 0)
{
return new LatestVersionResponse()
{
Version = "0.0.0.0",
};
}
response.Version = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault().Version;
}
return response;
}
[HttpPost]
[JwtTokenFilter]
public UploadVersionResponse UploadVersion(UploadVersionRequest request)
{
UploadVersionResponse response = new UploadVersionResponse();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
//Load relations first...
db.Roles.ToList();
db.Permissions.ToList();
db.UsersRoles.ToList();
db.RolesPermissions.ToList();
var user_guid = RequestToken.Object.UserGuid;
var user = new UserBuilder(db).Set(user_guid).WithRolesAndPermissions().Build();
if (user != null && user.HasPermission(Permissions.PublishPPCVersions))
{
var versions = db.TangoVersions.ToList().Where(x => x.MachineVersionGuid == request.MachineVersionGuid).OrderByDescending(x => Version.Parse(x.Version)).ToList();
var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == request.MachineVersionGuid);
TangoVersion latestVersion = new TangoVersion();
latestVersion.Version = "0.0.0.0";
if (versions.Count > 0)
{
latestVersion = versions.FirstOrDefault();
}
Version local_version = Version.Parse(request.Version);
if (local_version > Version.Parse(latestVersion.Version))
{
String newVersionFileName = $"{machine_version.Name} - Tango Version {local_version.ToString()}.tup";
var manager = new BlobStorageManager();
var container = manager.GetContainer(MachineServiceConfig.TANGO_VERSIONS_CONTAINER);
var blob = container.CreateEmptyBlob(newVersionFileName);
response.Token = Guid.NewGuid().ToString();
response.BlobAddress = blob.GenerateWriteSignature(TimeSpan.FromMinutes(30));
PPCPendingUpload pending_upload = new PPCPendingUpload()
{
UserGuid = user.Guid,
Comments = request.Comments,
Token = response.Token,
Version = request.Version,
BlobName = blob.Name,
MachineVersionGuid = request.MachineVersionGuid,
FirmwareVersion = request.FirmwareVersion,
};
if (request.WithInstaller)
{
String installerVersionFileName = Path.ChangeExtension(newVersionFileName, ".exe");
var installerBlob = container.CreateEmptyBlob(installerVersionFileName);
response.InstallerBlobAddress = installerBlob.GenerateWriteSignature(TimeSpan.FromMinutes(30));
pending_upload.InstallerBlobName = installerBlob.Name;
}
_pendingUploads.Add(pending_upload);
}
else
{
throw new ArgumentException("New version must be greater than latest version.");
}
}
else
{
throw new AuthenticationException("Invalid user credentials.");
}
}
return response;
}
[HttpPost]
[JwtTokenFilter]
public UploadCompletedResponse NotifyVersionUploadCompleted(UploadCompletedRequest request)
{
PPCPendingUpload upload = _pendingUploads.FirstOrDefault(x => x.Token == request.Token);
if (upload != null)
{
_pendingUploads.RemoveAll(x => x.Token == upload.Token);
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
db.TangoVersions.Add(new TangoVersion()
{
Comments = upload.Comments,
BlobName = upload.BlobName,
InstallerBlobName = upload.InstallerBlobName,
UserGuid = upload.UserGuid,
Version = upload.Version,
MachineVersionGuid = upload.MachineVersionGuid,
FirmwareVersion = upload.FirmwareVersion,
});
db.SaveChanges();
}
return new UploadCompletedResponse();
}
else
{
throw new AuthenticationException("Invalid upload token.");
}
}
[HttpPost]
public MachineVersionsResponse GetMachineVersions(MachineVersionsRequest request)
{
using (var db = ObservablesContextHelper.CreateContext())
{
return new MachineVersionsResponse()
{
MachineVersions = db.MachineVersions.ToList().Select(x => MachineVersionDTO.FromObservable(x)).ToList(),
};
}
}
[HttpPost]
public LoginResponse Login(LoginRequest request)
{
LoginResponse response = new LoginResponse();
using (ObservablesContext db = ObservablesContextHelper.CreateContext())
{
if (request.Mode == LoginMode.User)
{
var authResult = _ad_manager.ValidateUserCredentials(request.Email, request.Password);
if (!_ad_manager.CanUserAccessCurrentEnvironment(request.Email))
{
throw new AuthenticationException($"You do not have permissions to access the {MachineServiceConfig.DEPLOYMENT_SLOT.ToDescription()} environment.");
}
BasicHashGenerator hash = new BasicHashGenerator();
String pass = hash.Encrypt(request.Password);
var user = new UserBuilder(db).Set(x => x.Email.ToLower() == request.Email.ToLower() && x.Password == pass).Build();
if (user == null)
{
throw new AuthenticationException("Domain user found but the database entry validation failed.");
}
response.AccessToken = WebToken<TokenObject>.CreateNew(MachineServiceConfig.JWT_TOKEN_SECRET, new TokenObject()
{
Mode = LoginMode.User,
UserGuid = user.Guid,
}).AccessToken;
}
else if (request.Mode == LoginMode.Machine)
{
var machine = db.Machines.SingleOrDefault(x => x.SerialNumber == request.SerialNumber);
if (machine == null)
{
throw new AuthenticationException("Invalid serial number.");
}
response.AccessToken = WebToken<TokenObject>.CreateNew(MachineServiceConfig.JWT_TOKEN_SECRET, new TokenObject()
{
Mode = LoginMode.Machine,
MachineGuid = machine.Guid,
}).AccessToken;
}
}
return response;
}
#endregion
}
}