using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Manager.Helpers; using Manager.Interfaces.DTO; using Manager.Interfaces.Models; using Manager.Services; using ManagerService.Service.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Mqtt.Client.AspNetCore.Services; using Newtonsoft.Json; using NSwag.Annotations; namespace ManagerService.Controllers { [Authorize] // TODO Add ROLES (Roles = "Admin") [ApiController, Route("api/[controller]")] [OpenApiTag("Configuration", Description = "Configuration management")] public class ConfigurationController : ControllerBase { private ConfigurationDatabaseService _configurationService; private SectionDatabaseService _sectionService; private ResourceDatabaseService _resourceService; private ResourceDataDatabaseService _resourceDataService; private DeviceDatabaseService _deviceService; private readonly ILogger _logger; private readonly IConfiguration _configuration; public ConfigurationController(IConfiguration configuration, ILogger logger, ConfigurationDatabaseService configurationService, SectionDatabaseService sectionService, ResourceDatabaseService resourceService, ResourceDataDatabaseService resourceDataService, DeviceDatabaseService deviceService) { _logger = logger; _configuration = configuration; _configurationService = configurationService; _sectionService = sectionService; _resourceService = resourceService; _resourceDataService = resourceDataService; _deviceService = deviceService; } /// /// Get a list of all configuration (summary) /// /// id instance [AllowAnonymous] [ProducesResponseType(typeof(List), 200)] [ProducesResponseType(typeof(string), 500)] [HttpGet] public ObjectResult Get([FromQuery] string instanceId) { try { List configurations = _configurationService.GetAll(instanceId); List configurationDTOs = new List(); foreach(var configuration in configurations) { List sectionIds = _sectionService.GetAllIdsFromConfiguration(configuration.Id); ConfigurationDTO configurationDTO = configuration.ToDTO(sectionIds); configurationDTOs.Add(configurationDTO); } return new OkObjectResult(configurationDTOs.OrderBy(c => c.dateCreation)); } catch (Exception ex) { return new ObjectResult(ex.Message) { StatusCode = 500 }; } } /// /// Get a specific display configuration /// /// id configuration [AllowAnonymous] [ProducesResponseType(typeof(ConfigurationDTO), 200)] [ProducesResponseType(typeof(string), 404)] [ProducesResponseType(typeof(string), 500)] [HttpGet("{id}")] public ObjectResult GetDetail(string id) { try { Configuration configuration = _configurationService.GetById(id); if (configuration == null) throw new KeyNotFoundException("This configuration was not found"); List sectionIds = _sectionService.GetAllIdsFromConfiguration(id); return new OkObjectResult(configuration.ToDTO(sectionIds)); } catch (KeyNotFoundException ex) { return new NotFoundObjectResult(ex.Message) {}; } catch (Exception ex) { return new ObjectResult(ex.Message) { StatusCode = 500 }; } } /// /// Create a new configuration /// /// New configuration info [ProducesResponseType(typeof(ConfigurationDTO), 200)] [ProducesResponseType(typeof(string), 400)] [ProducesResponseType(typeof(string), 409)] [ProducesResponseType(typeof(string), 500)] [HttpPost] public ObjectResult Create([FromBody] ConfigurationDTO newConfiguration) { try { if (newConfiguration == null) throw new ArgumentNullException("Configuration param is null"); // Todo add some verification ? Configuration configuration = new Configuration(); configuration.InstanceId = newConfiguration.instanceId; configuration.Label = newConfiguration.label; configuration.Title = new List(); configuration.ImageId = newConfiguration.imageId; configuration.ImageSource = newConfiguration.imageSource; configuration.PrimaryColor = newConfiguration.primaryColor; configuration.SecondaryColor = newConfiguration.secondaryColor; configuration.Languages = _configuration.GetSection("SupportedLanguages").Get>(); //configuration.Languages = new List { "FR", "NL", "EN", "DE" }; // by default all languages configuration.Title = LanguageInit.Init("Title", configuration.Languages); configuration.DateCreation = DateTime.Now; configuration.IsMobile = newConfiguration.isMobile; configuration.IsTablet = newConfiguration.isTablet; configuration.IsOffline = newConfiguration.isOffline; Configuration configurationCreated = _configurationService.Create(configuration); return new OkObjectResult(configurationCreated.ToDTO(new List())); // Empty list } catch (ArgumentNullException ex) { return new BadRequestObjectResult(ex.Message) {}; } catch (InvalidOperationException ex) { return new ConflictObjectResult(ex.Message) {}; } catch (Exception ex) { return new ObjectResult(ex.Message) { StatusCode = 500 }; } } /// /// Update a configuration /// /// Configuration to update [ProducesResponseType(typeof(ConfigurationDTO), 200)] [ProducesResponseType(typeof(string), 400)] [ProducesResponseType(typeof(string), 404)] [ProducesResponseType(typeof(string), 500)] [HttpPut] public ObjectResult Update([FromBody] ConfigurationDTO updatedConfiguration) { try { if (updatedConfiguration == null) throw new ArgumentNullException("configuration param is null"); Configuration configuration = _configurationService.GetById(updatedConfiguration.id); if (configuration == null) throw new KeyNotFoundException("Configuration does not exist"); // Todo add some verification ? configuration.InstanceId = updatedConfiguration.instanceId; configuration.Label = updatedConfiguration.label; configuration.Title = updatedConfiguration.title; configuration.ImageId = updatedConfiguration.imageId; configuration.ImageSource = updatedConfiguration.imageSource; configuration.PrimaryColor = updatedConfiguration.primaryColor; configuration.SecondaryColor = updatedConfiguration.secondaryColor; configuration.Languages = updatedConfiguration.languages; configuration.IsMobile = updatedConfiguration.isMobile; configuration.IsTablet = updatedConfiguration.isTablet; configuration.IsOffline = updatedConfiguration.isOffline; Configuration configurationModified = _configurationService.Update(updatedConfiguration.id, configuration); // TODO HANDLE MqttClientService.PublishMessage($"config/{configurationModified.Id}", JsonConvert.SerializeObject(new PlayerMessageDTO() { configChanged = true })); List sectionIds = _sectionService.GetAllIdsFromConfiguration(configuration.Id); return new OkObjectResult(configurationModified.ToDTO(sectionIds)); } catch (ArgumentNullException ex) { return new BadRequestObjectResult(ex.Message) {}; } catch (KeyNotFoundException ex) { return new NotFoundObjectResult(ex.Message) {}; } catch (Exception ex) { return new ObjectResult(ex.Message) { StatusCode = 500 }; } } /// /// Delete a configuration /// /// Id of configuration to delete [ProducesResponseType(typeof(string), 202)] [ProducesResponseType(typeof(string), 400)] [ProducesResponseType(typeof(string), 404)] [ProducesResponseType(typeof(string), 500)] [HttpDelete("{id}")] public ObjectResult Delete(string id) { try { if (id == null) throw new ArgumentNullException("Configuration param is null"); if (!_configurationService.IsExist(id)) throw new KeyNotFoundException("Configuration does not exist"); _configurationService.Remove(id); // Delete config for all devices List devices = _deviceService.GetAllWithConfig(id); foreach (var device in devices) { device.Configuration = null; device.ConfigurationId = null; _deviceService.Update(device.Id, device); } // TODO MqttClientService.PublishMessage($"config/{id}", JsonConvert.SerializeObject(new PlayerMessageDTO() { configChanged = true, isDeleted = true })); return new ObjectResult("The configuration has been deleted") { StatusCode = 202 }; } catch (ArgumentNullException ex) { return new BadRequestObjectResult(ex.Message) { }; } catch (KeyNotFoundException ex) { return new NotFoundObjectResult(ex.Message) { }; } catch (Exception ex) { return new ObjectResult(ex.Message) { StatusCode = 500 }; } } /// /// Export a configuration /// /// Id of configuration to export /// Language to export [AllowAnonymous] [ProducesResponseType(typeof(FileContentResult), 200)] [ProducesResponseType(typeof(string), 400)] [ProducesResponseType(typeof(string), 404)] [ProducesResponseType(typeof(string), 500)] [HttpGet("{id}/export")] public FileContentResult Export(string id, [FromQuery] string language) { try { if (id == null) throw new ArgumentNullException("Configuration param is null"); Configuration configuration = _configurationService.GetById(id); if (configuration == null) throw new KeyNotFoundException("Configuration does not exist"); List sectionDTOs = _sectionService.GetAllFromConfiguration(configuration.Id).Select(s => s.ToDTO()).ToList(); List resourceDTOs = new List(); if (configuration.ImageId != null) { addResourceToList(resourceDTOs, configuration.ImageId); } foreach (var section in sectionDTOs) { if (section.imageId != null) { addResourceToList(resourceDTOs, section.imageId); } switch (section.type) { case SectionType.Map: MapDTO mapDTO = JsonConvert.DeserializeObject(section.data); if (mapDTO.iconResourceId != null) { addResourceToList(resourceDTOs, mapDTO.iconResourceId); } foreach (var point in mapDTO.points) { foreach (var image in point.images) { if (image.imageResourceId != null) { addResourceToList(resourceDTOs, image.imageResourceId); } } } break; case SectionType.Slider: SliderDTO sliderDTO = JsonConvert.DeserializeObject(section.data); foreach (var image in sliderDTO.images) { if (image.resourceId != null) { addResourceToList(resourceDTOs, image.resourceId); } } break; case SectionType.Quizz: QuizzDTO quizzDTO = JsonConvert.DeserializeObject(section.data); foreach (var question in quizzDTO.questions) { if (question.resourceId != null) { addResourceToList(resourceDTOs, question.resourceId); } } if (quizzDTO.bad_level != null) { if (quizzDTO.bad_level.resourceId != null) { addResourceToList(resourceDTOs, quizzDTO.bad_level.resourceId); } } if (quizzDTO.medium_level != null) { if (quizzDTO.medium_level.resourceId != null) { addResourceToList(resourceDTOs, quizzDTO.medium_level.resourceId); } } if (quizzDTO.good_level != null) { if (quizzDTO.good_level.resourceId != null) { addResourceToList(resourceDTOs, quizzDTO.good_level.resourceId); } } if (quizzDTO.great_level != null) { if (quizzDTO.great_level.resourceId != null) { addResourceToList(resourceDTOs, quizzDTO.great_level.resourceId); } } break; case SectionType.Article: ArticleDTO articleDTO = JsonConvert.DeserializeObject(section.data); foreach (var image in articleDTO.images) { if (image.resourceId != null) { addResourceToList(resourceDTOs, image.resourceId); } } // If not a language is used for export in manager, if one is the myvisit app var audios = language != null ? articleDTO.audioIds.Where(a => a.language == language) : articleDTO.audioIds; foreach (var audio in audios) { if (audio.value != null) { addResourceToList(resourceDTOs, audio.value); } } break; case SectionType.Menu: case SectionType.Web: case SectionType.Video: default: break; } } ExportConfigurationDTO toDownload = configuration.ToExportDTO(sectionDTOs, resourceDTOs); string jsonString = JsonConvert.SerializeObject(toDownload); var fileName = $"{configuration.Label}.json"; var mimeType = "application/json"; var fileBytes = Encoding.UTF8.GetBytes(jsonString); return new FileContentResult(fileBytes, mimeType) { FileDownloadName = fileName }; } catch (ArgumentNullException ex) { return null; //return new BadRequestObjectResult(ex.Message) { }; } catch (KeyNotFoundException ex) { return null; //return new NotFoundObjectResult(ex.Message) { }; } catch (Exception ex) { return null; //return new ObjectResult(ex.Message) { StatusCode = 500 }; } } /// /// Import a configuration /// /// Configuration to import [ProducesResponseType(typeof(string), 202)] [ProducesResponseType(typeof(string), 400)] [ProducesResponseType(typeof(string), 404)] [ProducesResponseType(typeof(string), 409)] [ProducesResponseType(typeof(string), 500)] [HttpPost("import")] public ObjectResult Import([FromBody] ExportConfigurationDTO exportConfiguration) { try { if (exportConfiguration == null) throw new ArgumentNullException("File to import is null"); Configuration configuration = _configurationService.GetById(exportConfiguration.id); if (configuration != null) throw new InvalidOperationException("Configuration already exist in the system"); configuration = new Configuration(); configuration.Id = exportConfiguration.id; configuration.InstanceId = exportConfiguration.instanceId; configuration.Label = exportConfiguration.label; configuration.Title = exportConfiguration.title; configuration.ImageId = exportConfiguration.imageId; configuration.ImageSource = exportConfiguration.imageSource; if (configuration.ImageId != null) { createResource(exportConfiguration.resources.Where(r => r.id == configuration.ImageId).FirstOrDefault()); } configuration.DateCreation = exportConfiguration.dateCreation; configuration.PrimaryColor = exportConfiguration.primaryColor; configuration.SecondaryColor = exportConfiguration.secondaryColor; configuration.Languages = exportConfiguration.languages; configuration.IsMobile = exportConfiguration.isMobile; configuration.IsTablet = exportConfiguration.isTablet; configuration.IsOffline = exportConfiguration.isOffline; _configurationService.Create(configuration); foreach (var section in exportConfiguration.sections.Where(s => !_sectionService.IsExist(s.id))) { Section newSection = new Section(); newSection.Id = section.id; newSection.InstanceId = section.instanceId; newSection.Label = section.label; newSection.Title = section.title; newSection.Description = section.description; newSection.Order = section.order; // if one day we can use same section in multiple configuration, need to change that newSection.Type = section.type; newSection.ImageId = section.imageId; newSection.ImageSource = section.imageSource; newSection.ConfigurationId = section.configurationId; newSection.IsSubSection = section.isSubSection; newSection.ParentId = section.parentId; newSection.Data = section.data; newSection.DateCreation = section.dateCreation; newSection.IsBeacon = section.isBeacon; newSection.BeaconId = section.beaconId; newSection.Latitude = section.latitude; newSection.Longitude = section.longitude; newSection.MeterZoneGPS = section.meterZoneGPS; if (newSection.ImageId != null) { createResource(exportConfiguration.resources.Where(r => r.id == newSection.ImageId).FirstOrDefault()); } _sectionService.Create(newSection); switch (section.type) { case SectionType.Map: MapDTO mapDTO = JsonConvert.DeserializeObject(section.data); if (mapDTO.iconResourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == mapDTO.iconResourceId).FirstOrDefault()); } foreach (var point in mapDTO.points) { foreach (var image in point.images) { if (image.imageResourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == image.imageResourceId).FirstOrDefault()); } } } break; case SectionType.Slider: SliderDTO sliderDTO = JsonConvert.DeserializeObject(section.data); foreach (var image in sliderDTO.images) { if (image.resourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == image.resourceId).FirstOrDefault()); } } break; case SectionType.Quizz: QuizzDTO quizzDTO = JsonConvert.DeserializeObject(section.data); foreach (var question in quizzDTO.questions) { if (question.resourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == question.resourceId).FirstOrDefault()); } } if (quizzDTO.bad_level != null) { if(quizzDTO.bad_level.resourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == quizzDTO.bad_level.resourceId).FirstOrDefault()); } } if (quizzDTO.medium_level != null) { if (quizzDTO.medium_level.resourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == quizzDTO.medium_level.resourceId).FirstOrDefault()); } } if (quizzDTO.good_level != null) { if (quizzDTO.good_level.resourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == quizzDTO.good_level.resourceId).FirstOrDefault()); } } if (quizzDTO.great_level != null) { if (quizzDTO.great_level.resourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == quizzDTO.great_level.resourceId).FirstOrDefault()); } } break; case SectionType.Article: ArticleDTO articleDTO = JsonConvert.DeserializeObject(section.data); foreach (var image in articleDTO.images) { if (image.resourceId != null) { createResource(exportConfiguration.resources.Where(r => r.id == image.resourceId).FirstOrDefault()); } } break; case SectionType.Menu: case SectionType.Web: case SectionType.Video: default: break; } } return new ObjectResult("The configuration has been successfully imported") { StatusCode = 202 }; } catch (ArgumentNullException ex) { return new BadRequestObjectResult(ex.Message) { }; } catch (KeyNotFoundException ex) { return new NotFoundObjectResult(ex.Message) { }; } catch (InvalidOperationException ex) { return new ConflictObjectResult(ex.Message) { }; } catch (Exception ex) { return new ObjectResult(ex.Message) { StatusCode = 500 }; } } private void createResource(ResourceDTO resourceExport) { if (resourceExport != null) { Resource resource = new Resource(); resource.Id = resourceExport.id; resource.InstanceId = resourceExport.instanceId; resource.Type = resourceExport.type; resource.Label = resourceExport.label; resource.DateCreation = resourceExport.dateCreation; //resource.Data = resourceExport.data; ResourceData resourceData = new ResourceData(); resourceData.ResourceId = resourceExport.id; resourceData.InstanceId = resourceExport.instanceId; resourceData.Data = resourceExport.data; if (!_resourceService.IsExist(resourceExport.id)) _resourceService.Create(resource); if (!_resourceDataService.IsExist(resourceExport.id)) _resourceDataService.Create(resourceData); } } private List addResourceToList(List resourceDTOs, string resourceId) { if (!resourceDTOs.Select(r => r.id).Contains(resourceId)) { Resource resource = _resourceService.GetById(resourceId); ResourceData resourceData = _resourceDataService.GetByResourceId(resourceId); if (resource != null && resourceData != null && !resourceDTOs.Any(r => r.id == resource.Id)) { resourceDTOs.Add(resource.ToDTO(resourceData.Data)); } } return resourceDTOs; } } }