using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.FSE.BL.CacheEntities; using Tango.FSE.Web.Messages; using Z.EntityFramework.Plus; namespace Tango.FSE.BL.Services { public class PublishedProcedureProjectsService : FSEServiceBase { private const string PUBLISHED_Procedure_PROJECTS_COLLECTION = "PublishedProcedureProjects"; private MemoryCacheDictionary _projectsCache; public PublishedProcedureProjectsService() { _projectsCache = MemoryCache.GetOrCreateCache(PUBLISHED_Procedure_PROJECTS_COLLECTION); } public Task> GetPublishedProcedureProjects(bool visibleOnly = true) { return DataResolver>.Builder.New() .ConfigureCascade(DataResolverNode.InMemoryCache, DataResolverNode.Web, DataResolverNode.Online, DataResolverNode.DiskCache) .InMemoryCache((context) => { var projects = _projectsCache.ToList().Where(x => x.IsVisible || !visibleOnly).Select(x => x.ToObservable()).ToList(); if (projects.Count == 0) { throw new IndexOutOfRangeException("The memory cache did not contain any procedure projects."); } if (!CurrentUser.HasPermission(Permissions.FSE_ViewInternalPublishedProcedures)) { projects.RemoveAll(x => x.ProjectVisibility == PublishedProcedureProjectVisibilities.Internal); } return projects.OrderBy(x => x.SortingIndex).ToList(); }) .Web((context) => { var response = WebClient.GetProcedures(new GetProceduresRequest() { GetOnlyVisible = visibleOnly }).GetAwaiter().GetResult(); var projects = response.Projects.Select(x => x.ToObservable()).ToList(); if (!CurrentUser.HasPermission(Permissions.FSE_ViewInternalPublishedProcedures)) { projects.RemoveAll(x => x.ProjectVisibility == PublishedProcedureProjectVisibilities.Internal); } try { using (var cache = DiskCache.CreateContext()) { var collection = cache.Database.GetCollection(PUBLISHED_Procedure_PROJECTS_COLLECTION); foreach (var project in projects) { var cachedProject = CachedPublishedProcedureProject.FromObservable(project); _projectsCache.Put(cachedProject.Guid, cachedProject); collection.Upsert(cachedProject); } } } catch (Exception ex) { LogManager.Log(ex, "Error caching published procedure projects."); } return projects.OrderBy(x => x.SortingIndex).ToList(); }) .Online((context) => { using (ObservablesContext db = ObservablesContext.CreateDefault()) { var select = db.PublishedProcedureProjects .Where(x => x.IsVisible || !visibleOnly) .Include(x => x.PublishedProcedureProjectsVersions) .Select(x => new { Project = x, LatestVersion = x.PublishedProcedureProjectsVersions.OrderByDescending(v => v.Version).FirstOrDefault() }).ToList(); List projects = new List(); foreach (var p in select) { PublishedProcedureProject project = p.Project; projects.Add(project); } if (!CurrentUser.HasPermission(Permissions.FSE_ViewInternalPublishedProcedures)) { projects.RemoveAll(x => x.ProjectVisibility == PublishedProcedureProjectVisibilities.Internal); } try { using (var cache = DiskCache.CreateContext()) { var collection = cache.Database.GetCollection(PUBLISHED_Procedure_PROJECTS_COLLECTION); foreach (var project in projects) { var cachedProject = CachedPublishedProcedureProject.FromObservable(project); _projectsCache.Put(cachedProject.Guid, cachedProject); collection.Upsert(cachedProject); } } } catch (Exception ex) { LogManager.Log(ex, "Error caching published procedure projects."); } return projects.OrderBy(x => x.SortingIndex).ToList(); } }) .DiskCache((context) => { using (var cache = DiskCache.CreateContext()) { var collection = cache.Database.GetCollection(PUBLISHED_Procedure_PROJECTS_COLLECTION); var cachedProjects = collection .Find(x => x.IsVisible || !visibleOnly) .ToList(); foreach (var cachedProject in cachedProjects) { _projectsCache.Put(cachedProject.Guid, cachedProject); } var projects = cachedProjects.Select(x => x.ToObservable()).OrderBy(x => x.SortingIndex).ToList(); if (!CurrentUser.HasPermission(Permissions.FSE_ViewInternalPublishedProcedures)) { projects.RemoveAll(x => x.ProjectVisibility == PublishedProcedureProjectVisibilities.Internal); } return projects; } }) .BuildExecuteAsync(); } public Task PublishProcedureProject(String projectGuid, String name, String description, String projectJson, PublishedProcedureProjectVisibilities visibility) { return Task.Factory.StartNew(() => { if (!CurrentUser.HasPermission(Permissions.FSE_PublishProcedureProjects)) { throw new AuthorizationException(); } if (!ConnectivityProvider.CheckOnline()) { throw new InternetConnectionException(); } if (!name.IsNotNullOrEmpty()) { throw new ArgumentException("Cannot publish a project with an empty name."); } PublishedProcedureProject project = null; using (ObservablesContext db = ObservablesContext.CreateDefault()) { int version = 1; if (projectGuid == null) { project = new PublishedProcedureProject(); project.PublishDate = DateTime.UtcNow; db.PublishedProcedureProjects.Add(project); } else { project = db.PublishedProcedureProjects.SingleOrDefault(x => x.Guid == projectGuid); int? lastVersion = db.PublishedProcedureProjectsVersions.Where(x => x.PublishedProcedureProjectGuid == project.Guid).Select(x => x.Version).OrderByDescending(x => x).FirstOrDefault(); if (lastVersion != null) { version = lastVersion.Value + 1; } if (!project.IsVisible) { project.PublishDate = DateTime.UtcNow; } } project.Name = name; project.LastUpdated = DateTime.UtcNow; project.Description = description; project.ProjectVisibility = visibility; project.IsVisible = true; PublishedProcedureProjectsVersion projectVersion = new PublishedProcedureProjectsVersion(); projectVersion.Author = CurrentUser.Contact.FullName; projectVersion.Version = version; projectVersion.ProjectJsonString = projectJson; projectVersion.PublishedProcedureProject = project; projectVersion.PublishedProcedureProjectGuid = project.Guid; project.PublishedProcedureProjectsVersions.Add(projectVersion); db.SaveChanges(); var versionsCount = db.PublishedProcedureProjectsVersions.Where(x => x.PublishedProcedureProjectGuid == project.Guid).Count(); if (versionsCount > 10) { var firstVersion = db.PublishedProcedureProjectsVersions.Where(x => x.PublishedProcedureProjectGuid == project.Guid).OrderBy(x => x.Version).First(); db.PublishedProcedureProjectsVersions.Remove(firstVersion); db.SaveChanges(); } using (var cache = DiskCache.CreateContext()) { var cachedProject = CachedPublishedProcedureProject.FromObservable(project); var collection = cache.Database.GetCollection(PUBLISHED_Procedure_PROJECTS_COLLECTION); collection.Upsert(cachedProject); _projectsCache.Put(project.Guid, cachedProject); } return project; } }); } public Task UnPublishProcedureProject(PublishedProcedureProject project) { return Task.Factory.StartNew(() => { using (ObservablesContext db = ObservablesContext.CreateDefault()) { db.PublishedProcedureProjects.Where(x => x.Guid == project.Guid).Update(x => new PublishedProcedureProject() { IsVisible = false }); project.IsVisible = false; using (var cache = DiskCache.CreateContext()) { var collection = cache.Database.GetCollection(PUBLISHED_Procedure_PROJECTS_COLLECTION); var cachedProject = collection.FindOne(x => x.Guid == project.Guid); if (cachedProject != null) { cachedProject.IsVisible = false; collection.Update(cachedProject); } _projectsCache.Put(project.Guid, cachedProject); } return project; } }); } } }