Lot B : geler le schéma, plus sécurité rapide et calculateur de stockage
LOT B — une seule migration EF (LotB_FreezeSchema) : - SectionMap.MapResourceId → IconResourceId. L'écart (g) de la bascule tombe avec. Il fallait renommer aussi la propriété de navigation MapResource : la convention EF l'appariait au FK, la laisser aurait fabriqué un FK fantôme. Elle n'était utilisée nulle part ailleurs. - SectionEvent.ParcoursIds supprimé (champ, DTO, SectionFactory, et une initialisation dans un montage de test). - Instance.IsImageWatermark remplace le `instanceId == "633ee379…"` en dur de ResourceController. EF a généré un RenameColumn, pas un drop+add : les icônes déjà configurées survivent. L'avertissement de perte de données ne porte que sur le DropColumn de ParcoursIds, ce qui est l'intention. Non fait, et c'était une erreur de doc : « supprimer SectionEvent.IconResourceId ». Ce champ n'existe pas — la ligne visée appartient à la classe imbriquée MapAnnotation, partagée par SectionEvent, SectionAgenda et SectionMap, lue par cinq contrôleurs et par GetReferencedResourceIds. La supprimer aurait cassé les icônes d'annotation des trois types et la collecte offline. SÉCURITÉ (lot A, même repo) : - AuthenticationController.Authenticate : un bloc #if DEBUG écrasait l'email et le mot de passe reçus par un compte de test, donc toute compilation en Debug authentifiait n'importe quelle saisie. Retiré. - EnableSensitiveDataLogging (qui écrit les valeurs des paramètres dans les logs) passe sous #if DEBUG, l'idiome déjà employé dans Startup.cs pour le CORS et Hangfire. Le Dockerfile publiant en -c Release, c'est un verrou réel. LOT C1 : - Calculateur StoragePath/SizeBytes extrait dans Helpers/ResourceStorage.cs, avec 13 tests fixant l'invariant des types URL. Il ferme le lien L5 : le backfill (C2) et l'écart (e) de la migration appelleront le même code. - L'extraction a révélé la divergence qu'elle devait empêcher : des deux chemins de création de ResourceController, le chemin multipart écrivait SizeBytes mais laissait StoragePath nul. dotnet build Debug et Release verts, dotnet test 143/143 (130 + 13). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
18e4240f0f
commit
7625487806
@ -43,8 +43,7 @@ namespace ManagerService.Tests.Controllers
|
|||||||
ConfigurationId = "c1",
|
ConfigurationId = "c1",
|
||||||
Title = EmptyTranslations(),
|
Title = EmptyTranslations(),
|
||||||
Description = EmptyTranslations(),
|
Description = EmptyTranslations(),
|
||||||
Programme = new List<ProgrammeBlock>(),
|
Programme = new List<ProgrammeBlock>()
|
||||||
ParcoursIds = new List<string>()
|
|
||||||
});
|
});
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
|
|
||||||
|
|||||||
62
ManagerService.Tests/Helpers/ResourceStorageTests.cs
Normal file
62
ManagerService.Tests/Helpers/ResourceStorageTests.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using ManagerService.Data;
|
||||||
|
using ManagerService.Helpers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ManagerService.Tests.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Le calculateur est appelé par la création, le backfill et MigrationController.
|
||||||
|
/// Ces tests fixent la distinction qu'ils perdaient chacun de leur côté : un type
|
||||||
|
/// URL n'a pas de blob, donc ni chemin de stockage ni poids au quota.
|
||||||
|
/// </summary>
|
||||||
|
public class ResourceStorageTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(ResourceType.Image)]
|
||||||
|
[InlineData(ResourceType.Video)]
|
||||||
|
[InlineData(ResourceType.Audio)]
|
||||||
|
[InlineData(ResourceType.PDF)]
|
||||||
|
[InlineData(ResourceType.JSON)]
|
||||||
|
[InlineData(ResourceType.Word)]
|
||||||
|
[InlineData(ResourceType.PowerPoint)]
|
||||||
|
[InlineData(ResourceType.Text)]
|
||||||
|
public void Apply_BlobType_WritesPathAndSize(ResourceType type)
|
||||||
|
{
|
||||||
|
var resource = new Resource { Id = "res-1", InstanceId = "inst-1", Type = type };
|
||||||
|
|
||||||
|
ResourceStorage.Apply(resource, 4096);
|
||||||
|
|
||||||
|
Assert.Equal("pictures/inst-1/res-1", resource.StoragePath);
|
||||||
|
Assert.Equal(4096, resource.SizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(ResourceType.ImageUrl)]
|
||||||
|
[InlineData(ResourceType.VideoUrl)]
|
||||||
|
[InlineData(ResourceType.JSONUrl)]
|
||||||
|
public void Apply_UrlType_WritesNothing(ResourceType type)
|
||||||
|
{
|
||||||
|
var resource = new Resource { Id = "res-1", InstanceId = "inst-1", Type = type };
|
||||||
|
|
||||||
|
ResourceStorage.Apply(resource, 4096);
|
||||||
|
|
||||||
|
Assert.Null(resource.StoragePath);
|
||||||
|
// Reste à 0 : un média hébergé ailleurs ne doit pas peser sur le quota.
|
||||||
|
Assert.Equal(0, resource.SizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PathFor_IsDeterministic_SoBackfillCanRebuildIt()
|
||||||
|
{
|
||||||
|
Assert.Equal(
|
||||||
|
ResourceStorage.PathFor(ResourceType.Image, "inst-1", "res-1"),
|
||||||
|
ResourceStorage.PathFor(ResourceType.Image, "inst-1", "res-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PathFor_UrlType_IsNull()
|
||||||
|
{
|
||||||
|
Assert.Null(ResourceStorage.PathFor(ResourceType.ImageUrl, "inst-1", "res-1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -60,10 +60,9 @@ namespace ManagerService.Service.Controllers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if DEBUG
|
// Retiré le 2026-08-11 : un bloc `#if DEBUG` écrasait ici l'email et le
|
||||||
email = "test@email.be";
|
// mot de passe reçus par un compte de test, donc toute compilation en
|
||||||
password = "kljqsdkljqsd"; // password = "kljqsdkljqsd"; // W/7aj4NB60i3YFKJq50pbw==
|
// Debug authentifiait n'importe qui en tant que test@email.be.
|
||||||
#endif
|
|
||||||
// Set user token ?
|
// Set user token ?
|
||||||
var user = _myInfoMateDbContext.Users.FirstOrDefault(u => u.Email.ToLower() == email.ToLower());
|
var user = _myInfoMateDbContext.Users.FirstOrDefault(u => u.Email.ToLower() == email.ToLower());
|
||||||
//var user = _UserDatabaseService.GetByEmail(email.ToLower());
|
//var user = _UserDatabaseService.GetByEmail(email.ToLower());
|
||||||
|
|||||||
@ -466,7 +466,7 @@ namespace ManagerService.Controllers
|
|||||||
MapMapType = dto?.mapType,
|
MapMapType = dto?.mapType,
|
||||||
MapTypeMapbox = dto?.mapTypeMapbox,
|
MapTypeMapbox = dto?.mapTypeMapbox,
|
||||||
MapMapProvider = dto?.mapProvider,
|
MapMapProvider = dto?.mapProvider,
|
||||||
MapResourceId = dto?.iconResourceId,
|
IconResourceId = dto?.iconResourceId,
|
||||||
MapCenterLatitude = dto?.latitude,
|
MapCenterLatitude = dto?.latitude,
|
||||||
MapCenterLongitude = dto?.longitude,
|
MapCenterLongitude = dto?.longitude,
|
||||||
MapCategories = dto?.categories?.Select(c => new CategorieDTO
|
MapCategories = dto?.categories?.Select(c => new CategorieDTO
|
||||||
|
|||||||
@ -260,14 +260,9 @@ namespace ManagerService.Controllers
|
|||||||
{
|
{
|
||||||
file.CopyTo(ms);
|
file.CopyTo(ms);
|
||||||
var fileBytes = ms.ToArray();
|
var fileBytes = ms.ToArray();
|
||||||
if (resourceType == ResourceType.Image)
|
if (resourceType == ResourceType.Image && IsWatermarkEnabled(instanceId))
|
||||||
{
|
{
|
||||||
bool isFort = instanceId == "633ee379d9405f32f166f047"; // If fort saint heribert, TODO add watermark in configuration and model
|
fileBytes = ImageHelper.ResizeAndAddWatermark(fileBytes, true, MaxWidth, MaxHeight);
|
||||||
|
|
||||||
if(isFort) // TODO We need to know for which purpose (mobile or tablet)
|
|
||||||
{
|
|
||||||
fileBytes = ImageHelper.ResizeAndAddWatermark(fileBytes, isFort, MaxWidth, MaxHeight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stringResult = Convert.ToBase64String(fileBytes);
|
stringResult = Convert.ToBase64String(fileBytes);
|
||||||
}
|
}
|
||||||
@ -283,7 +278,7 @@ namespace ManagerService.Controllers
|
|||||||
resource.DateCreation = DateTime.Now.ToUniversalTime();
|
resource.DateCreation = DateTime.Now.ToUniversalTime();
|
||||||
resource.InstanceId = instanceId;
|
resource.InstanceId = instanceId;
|
||||||
resource.Id = idService.GenerateHexId();
|
resource.Id = idService.GenerateHexId();
|
||||||
resource.SizeBytes = file.Length;
|
ResourceStorage.Apply(resource, file.Length);
|
||||||
|
|
||||||
_myInfoMateDbContext.Add(resource);
|
_myInfoMateDbContext.Add(resource);
|
||||||
_myInfoMateDbContext.SaveChanges();
|
_myInfoMateDbContext.SaveChanges();
|
||||||
@ -339,15 +334,7 @@ namespace ManagerService.Controllers
|
|||||||
resource.InstanceId = newResource.instanceId;
|
resource.InstanceId = newResource.instanceId;
|
||||||
resource.Id = idService.GenerateHexId();
|
resource.Id = idService.GenerateHexId();
|
||||||
|
|
||||||
// Les types URL pointent hors du bucket : ni chemin de stockage, ni poids à compter dans le quota.
|
ResourceStorage.Apply(resource, newResource.sizeBytes);
|
||||||
bool hasBlob = resource.Type != ResourceType.ImageUrl
|
|
||||||
&& resource.Type != ResourceType.VideoUrl
|
|
||||||
&& resource.Type != ResourceType.JSONUrl;
|
|
||||||
if (hasBlob)
|
|
||||||
{
|
|
||||||
resource.StoragePath = $"pictures/{resource.InstanceId}/{resource.Id}";
|
|
||||||
resource.SizeBytes = newResource.sizeBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
_myInfoMateDbContext.Add(resource);
|
_myInfoMateDbContext.Add(resource);
|
||||||
_myInfoMateDbContext.SaveChanges();
|
_myInfoMateDbContext.SaveChanges();
|
||||||
@ -466,7 +453,7 @@ namespace ManagerService.Controllers
|
|||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
case SectionMap map:
|
case SectionMap map:
|
||||||
map.MapResourceId = map.MapResourceId == id ? null : map.MapResourceId;
|
map.IconResourceId = map.IconResourceId == id ? null : map.IconResourceId;
|
||||||
List<GeoPoint> geoPoints = _myInfoMateDbContext.GeoPoints.Where(s => s.SectionMapId == section.Id).ToList();
|
List<GeoPoint> geoPoints = _myInfoMateDbContext.GeoPoints.Where(s => s.SectionMapId == section.Id).ToList();
|
||||||
foreach (var point in geoPoints)
|
foreach (var point in geoPoints)
|
||||||
{
|
{
|
||||||
@ -716,5 +703,15 @@ namespace ManagerService.Controllers
|
|||||||
return new ObjectResult(ex.Message) { StatusCode = 500 };
|
return new ObjectResult(ex.Message) { StatusCode = 500 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Le filigrane est un réglage d'instance depuis le 2026-08-11. Auparavant
|
||||||
|
/// un `instanceId == "633ee379…"` en dur ne l'activait que pour Fort Saint-Héribert.
|
||||||
|
/// </summary>
|
||||||
|
private bool IsWatermarkEnabled(string instanceId) =>
|
||||||
|
_myInfoMateDbContext.Instances
|
||||||
|
.Where(i => i.Id == instanceId)
|
||||||
|
.Select(i => i.IsImageWatermark)
|
||||||
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ namespace ManagerService.DTOs
|
|||||||
public bool? isVR { get; set; }
|
public bool? isVR { get; set; }
|
||||||
|
|
||||||
public bool? isAssistant { get; set; }
|
public bool? isAssistant { get; set; }
|
||||||
|
public bool? isImageWatermark { get; set; }
|
||||||
|
|
||||||
public string? guideName { get; set; }
|
public string? guideName { get; set; }
|
||||||
public string? guidePersonaPrompt { get; set; }
|
public string? guidePersonaPrompt { get; set; }
|
||||||
|
|||||||
@ -10,7 +10,6 @@ namespace Manager.DTOs
|
|||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
public string? BaseSectionMapId { get; set; }
|
public string? BaseSectionMapId { get; set; }
|
||||||
public List<string> ParcoursIds { get; set; }
|
|
||||||
public List<MapAnnotationDTO> GlobalMapAnnotations { get; set; } = new();
|
public List<MapAnnotationDTO> GlobalMapAnnotations { get; set; } = new();
|
||||||
public List<ProgrammeBlock> Programme { get; set; } = new();
|
public List<ProgrammeBlock> Programme { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,12 @@ namespace ManagerService.Data
|
|||||||
|
|
||||||
public bool IsAssistant { get; set; }
|
public bool IsAssistant { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appose le filigrane du lieu sur les images téléversées. Remplace le
|
||||||
|
/// `instanceId == "633ee379…"` en dur de ResourceController.Create.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsImageWatermark { get; set; }
|
||||||
|
|
||||||
/// <summary>Nom du guide affiché au visiteur, libre. Ex: "Léon".</summary>
|
/// <summary>Nom du guide affiché au visiteur, libre. Ex: "Léon".</summary>
|
||||||
public string? GuideName { get; set; }
|
public string? GuideName { get; set; }
|
||||||
|
|
||||||
@ -118,6 +124,7 @@ namespace ManagerService.Data
|
|||||||
isWeb = IsWeb,
|
isWeb = IsWeb,
|
||||||
isVR = IsVR,
|
isVR = IsVR,
|
||||||
isAssistant = IsAssistant,
|
isAssistant = IsAssistant,
|
||||||
|
isImageWatermark = IsImageWatermark,
|
||||||
guideName = GuideName,
|
guideName = GuideName,
|
||||||
guidePersonaPrompt = GuidePersonaPrompt,
|
guidePersonaPrompt = GuidePersonaPrompt,
|
||||||
guideVoiceId = GuideVoiceId,
|
guideVoiceId = GuideVoiceId,
|
||||||
@ -155,6 +162,7 @@ namespace ManagerService.Data
|
|||||||
IsWeb = instanceDTO.isWeb ?? false;
|
IsWeb = instanceDTO.isWeb ?? false;
|
||||||
IsVR = instanceDTO.isVR ?? false;
|
IsVR = instanceDTO.isVR ?? false;
|
||||||
IsAssistant = instanceDTO.isAssistant ?? false;
|
IsAssistant = instanceDTO.isAssistant ?? false;
|
||||||
|
IsImageWatermark = instanceDTO.isImageWatermark ?? false;
|
||||||
if (instanceDTO.guideName != null)
|
if (instanceDTO.guideName != null)
|
||||||
GuideName = instanceDTO.guideName;
|
GuideName = instanceDTO.guideName;
|
||||||
if (instanceDTO.guidePersonaPrompt != null)
|
if (instanceDTO.guidePersonaPrompt != null)
|
||||||
|
|||||||
@ -24,8 +24,6 @@ namespace ManagerService.Data.SubSection
|
|||||||
public SectionMap? BaseMap { get; set; }
|
public SectionMap? BaseMap { get; set; }
|
||||||
public List<MapAnnotation> GlobalMapAnnotations { get; set; } = new();
|
public List<MapAnnotation> GlobalMapAnnotations { get; set; } = new();
|
||||||
public List<ProgrammeBlock> Programme { get; set; } = new();
|
public List<ProgrammeBlock> Programme { get; set; } = new();
|
||||||
[Column(TypeName = "jsonb")]
|
|
||||||
public List<string> ParcoursIds { get; set; } = new(); // Liens vers GeoPoints spécifiques
|
|
||||||
|
|
||||||
public override string GetEmbeddableText(string language) =>
|
public override string GetEmbeddableText(string language) =>
|
||||||
JoinText(new[]
|
JoinText(new[]
|
||||||
|
|||||||
@ -22,8 +22,8 @@ namespace ManagerService.Data.SubSection
|
|||||||
public MapTypeMapBox? MapTypeMapbox { get; set; } // Default = standard for MapBox
|
public MapTypeMapBox? MapTypeMapbox { get; set; } // Default = standard for MapBox
|
||||||
public MapProvider? MapMapProvider { get; set; } // Default = Google
|
public MapProvider? MapMapProvider { get; set; } // Default = Google
|
||||||
public List<GeoPoint> MapPoints { get; set; }
|
public List<GeoPoint> MapPoints { get; set; }
|
||||||
public string MapResourceId { get; set; }
|
public string IconResourceId { get; set; }
|
||||||
public Resource MapResource { get; set; } // Icon
|
public Resource IconResource { get; set; } // Icon
|
||||||
[Required]
|
[Required]
|
||||||
[Column(TypeName = "jsonb")]
|
[Column(TypeName = "jsonb")]
|
||||||
public List<CategorieDTO> MapCategories { get; set; }
|
public List<CategorieDTO> MapCategories { get; set; }
|
||||||
@ -42,7 +42,7 @@ namespace ManagerService.Data.SubSection
|
|||||||
|
|
||||||
public override IEnumerable<string> GetReferencedResourceIds(string language = null) =>
|
public override IEnumerable<string> GetReferencedResourceIds(string language = null) =>
|
||||||
BaseResourceIds()
|
BaseResourceIds()
|
||||||
.Concat(ResourceId(MapResourceId))
|
.Concat(ResourceId(IconResourceId))
|
||||||
.Concat((MapCategories ?? new List<CategorieDTO>())
|
.Concat((MapCategories ?? new List<CategorieDTO>())
|
||||||
.SelectMany(c => ResourceId(c.resourceDTO?.id)))
|
.SelectMany(c => ResourceId(c.resourceDTO?.id)))
|
||||||
.Concat((MapPoints ?? new List<GeoPoint>())
|
.Concat((MapPoints ?? new List<GeoPoint>())
|
||||||
@ -74,7 +74,7 @@ namespace ManagerService.Data.SubSection
|
|||||||
mapType = MapMapType,
|
mapType = MapMapType,
|
||||||
mapTypeMapbox = MapTypeMapbox,
|
mapTypeMapbox = MapTypeMapbox,
|
||||||
mapProvider = MapMapProvider,
|
mapProvider = MapMapProvider,
|
||||||
iconResourceId = MapResourceId,
|
iconResourceId = IconResourceId,
|
||||||
categories = MapCategories,
|
categories = MapCategories,
|
||||||
centerLatitude = MapCenterLatitude,
|
centerLatitude = MapCenterLatitude,
|
||||||
centerLongitude = MapCenterLongitude
|
centerLongitude = MapCenterLongitude
|
||||||
|
|||||||
45
ManagerService/Helpers/ResourceStorage.cs
Normal file
45
ManagerService/Helpers/ResourceStorage.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using ManagerService.Data;
|
||||||
|
|
||||||
|
namespace ManagerService.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Seule source de vérité pour StoragePath et SizeBytes d'une Resource.
|
||||||
|
///
|
||||||
|
/// Trois chemins écrivent ces colonnes : la création par téléversement et la
|
||||||
|
/// création par JSON (ResourceController), le backfill des lignes existantes,
|
||||||
|
/// et MigrationController (écart e de la bascule). Chacun calculant pour son
|
||||||
|
/// compte, ils divergeaient déjà : le chemin multipart renseignait SizeBytes
|
||||||
|
/// mais laissait StoragePath nul.
|
||||||
|
/// </summary>
|
||||||
|
public static class ResourceStorage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Les types URL pointent hors du bucket : ni chemin de stockage, ni poids
|
||||||
|
/// à compter dans le quota. C'est la distinction que les appelants perdaient.
|
||||||
|
/// </summary>
|
||||||
|
public static bool HasBlob(ResourceType type) =>
|
||||||
|
type != ResourceType.ImageUrl
|
||||||
|
&& type != ResourceType.VideoUrl
|
||||||
|
&& type != ResourceType.JSONUrl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Chemin déterministe dans le bucket — reconstructible sans lire la ligne,
|
||||||
|
/// ce dont le backfill dépend. Null pour un type sans blob.
|
||||||
|
/// </summary>
|
||||||
|
public static string PathFor(ResourceType type, string instanceId, string resourceId) =>
|
||||||
|
HasBlob(type) ? $"pictures/{instanceId}/{resourceId}" : null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renseigne les deux colonnes de stockage. Ne touche à rien pour un type URL,
|
||||||
|
/// dont SizeBytes doit rester à 0 pour ne pas peser sur le quota.
|
||||||
|
/// </summary>
|
||||||
|
public static void Apply(Resource resource, long sizeBytes)
|
||||||
|
{
|
||||||
|
if (!HasBlob(resource.Type))
|
||||||
|
return;
|
||||||
|
|
||||||
|
resource.StoragePath = PathFor(resource.Type, resource.InstanceId, resource.Id);
|
||||||
|
resource.SizeBytes = sizeBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1883
ManagerService/Migrations/20260811130738_LotB_FreezeSchema.Designer.cs
generated
Normal file
1883
ManagerService/Migrations/20260811130738_LotB_FreezeSchema.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,82 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ManagerService.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class LotB_FreezeSchema : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Sections_Resources_MapResourceId",
|
||||||
|
table: "Sections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ParcoursIds",
|
||||||
|
table: "Sections");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "MapResourceId",
|
||||||
|
table: "Sections",
|
||||||
|
newName: "IconResourceId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Sections_MapResourceId",
|
||||||
|
table: "Sections",
|
||||||
|
newName: "IX_Sections_IconResourceId");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsImageWatermark",
|
||||||
|
table: "Instances",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Sections_Resources_IconResourceId",
|
||||||
|
table: "Sections",
|
||||||
|
column: "IconResourceId",
|
||||||
|
principalTable: "Resources",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Sections_Resources_IconResourceId",
|
||||||
|
table: "Sections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsImageWatermark",
|
||||||
|
table: "Instances");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "IconResourceId",
|
||||||
|
table: "Sections",
|
||||||
|
newName: "MapResourceId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Sections_IconResourceId",
|
||||||
|
table: "Sections",
|
||||||
|
newName: "IX_Sections_MapResourceId");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<List<string>>(
|
||||||
|
name: "ParcoursIds",
|
||||||
|
table: "Sections",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Sections_Resources_MapResourceId",
|
||||||
|
table: "Sections",
|
||||||
|
column: "MapResourceId",
|
||||||
|
principalTable: "Resources",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -465,6 +465,9 @@ namespace ManagerService.Migrations
|
|||||||
b.Property<bool>("IsAssistant")
|
b.Property<bool>("IsAssistant")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("IsImageWatermark")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
b.Property<bool>("IsMobile")
|
b.Property<bool>("IsMobile")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
@ -1398,9 +1401,6 @@ namespace ManagerService.Migrations
|
|||||||
b.Property<DateTime?>("EndDate")
|
b.Property<DateTime?>("EndDate")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<List<string>>("ParcoursIds")
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartDate")
|
b.Property<DateTime?>("StartDate")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
@ -1442,6 +1442,9 @@ namespace ManagerService.Migrations
|
|||||||
{
|
{
|
||||||
b.HasBaseType("ManagerService.Data.Section");
|
b.HasBaseType("ManagerService.Data.Section");
|
||||||
|
|
||||||
|
b.Property<string>("IconResourceId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<bool>("IsListViewEnabled")
|
b.Property<bool>("IsListViewEnabled")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
@ -1461,16 +1464,13 @@ namespace ManagerService.Migrations
|
|||||||
b.Property<int?>("MapMapType")
|
b.Property<int?>("MapMapType")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.Property<string>("MapResourceId")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int?>("MapTypeMapbox")
|
b.Property<int?>("MapTypeMapbox")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.Property<int>("MapZoom")
|
b.Property<int>("MapZoom")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.HasIndex("MapResourceId");
|
b.HasIndex("IconResourceId");
|
||||||
|
|
||||||
b.HasDiscriminator().HasValue("Map");
|
b.HasDiscriminator().HasValue("Map");
|
||||||
});
|
});
|
||||||
@ -1806,11 +1806,11 @@ namespace ManagerService.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("ManagerService.Data.SubSection.SectionMap", b =>
|
modelBuilder.Entity("ManagerService.Data.SubSection.SectionMap", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("ManagerService.Data.Resource", "MapResource")
|
b.HasOne("ManagerService.Data.Resource", "IconResource")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("MapResourceId");
|
.HasForeignKey("IconResourceId");
|
||||||
|
|
||||||
b.Navigation("MapResource");
|
b.Navigation("IconResource");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("ManagerService.Data.SubSection.SectionParcours", b =>
|
modelBuilder.Entity("ManagerService.Data.SubSection.SectionParcours", b =>
|
||||||
|
|||||||
@ -31,8 +31,7 @@ namespace ManagerService.Services
|
|||||||
},
|
},
|
||||||
SectionType.Event => new SectionEvent
|
SectionType.Event => new SectionEvent
|
||||||
{
|
{
|
||||||
Programme = new List<SectionEvent.ProgrammeBlock>(),
|
Programme = new List<SectionEvent.ProgrammeBlock>()
|
||||||
ParcoursIds = new List<string>()
|
|
||||||
},
|
},
|
||||||
SectionType.Map => new SectionMap
|
SectionType.Map => new SectionMap
|
||||||
{
|
{
|
||||||
@ -196,7 +195,6 @@ namespace ManagerService.Services
|
|||||||
Type = dto.type,
|
Type = dto.type,
|
||||||
StartDate = sectionEventDTO.StartDate?.ToUniversalTime(),
|
StartDate = sectionEventDTO.StartDate?.ToUniversalTime(),
|
||||||
EndDate = sectionEventDTO.EndDate?.ToUniversalTime(),
|
EndDate = sectionEventDTO.EndDate?.ToUniversalTime(),
|
||||||
ParcoursIds = sectionEventDTO.ParcoursIds,
|
|
||||||
BaseSectionMapId = sectionEventDTO.BaseSectionMapId,
|
BaseSectionMapId = sectionEventDTO.BaseSectionMapId,
|
||||||
//Programmes = // TODO specific
|
//Programmes = // TODO specific
|
||||||
},
|
},
|
||||||
@ -224,7 +222,7 @@ namespace ManagerService.Services
|
|||||||
MapMapType = mapDTO.mapType,
|
MapMapType = mapDTO.mapType,
|
||||||
MapTypeMapbox = mapDTO.mapTypeMapbox,
|
MapTypeMapbox = mapDTO.mapTypeMapbox,
|
||||||
MapMapProvider = mapDTO.mapProvider,
|
MapMapProvider = mapDTO.mapProvider,
|
||||||
MapResourceId = mapDTO.iconResourceId,
|
IconResourceId = mapDTO.iconResourceId,
|
||||||
MapCenterLatitude = mapDTO.centerLatitude,
|
MapCenterLatitude = mapDTO.centerLatitude,
|
||||||
MapCenterLongitude = mapDTO.centerLongitude,
|
MapCenterLongitude = mapDTO.centerLongitude,
|
||||||
MapCategories = mapDTO.categories,
|
MapCategories = mapDTO.categories,
|
||||||
@ -526,7 +524,6 @@ namespace ManagerService.Services
|
|||||||
type = sectionEvent.Type,
|
type = sectionEvent.Type,
|
||||||
StartDate = sectionEvent.StartDate?.Year > 1000 ? sectionEvent.StartDate : null,
|
StartDate = sectionEvent.StartDate?.Year > 1000 ? sectionEvent.StartDate : null,
|
||||||
EndDate = sectionEvent.EndDate?.Year > 1000 ? sectionEvent.EndDate : null,
|
EndDate = sectionEvent.EndDate?.Year > 1000 ? sectionEvent.EndDate : null,
|
||||||
ParcoursIds = sectionEvent.ParcoursIds,
|
|
||||||
BaseSectionMapId = sectionEvent.BaseSectionMapId,
|
BaseSectionMapId = sectionEvent.BaseSectionMapId,
|
||||||
GlobalMapAnnotations = sectionEvent.GlobalMapAnnotations?.Select(ma => ma.ToDTO()).ToList() ?? new(),
|
GlobalMapAnnotations = sectionEvent.GlobalMapAnnotations?.Select(ma => ma.ToDTO()).ToList() ?? new(),
|
||||||
// Programme TODO specific
|
// Programme TODO specific
|
||||||
@ -556,7 +553,7 @@ namespace ManagerService.Services
|
|||||||
mapType = map.MapMapType,
|
mapType = map.MapMapType,
|
||||||
mapTypeMapbox = map.MapTypeMapbox,
|
mapTypeMapbox = map.MapTypeMapbox,
|
||||||
mapProvider = map.MapMapProvider,
|
mapProvider = map.MapMapProvider,
|
||||||
iconResourceId = map.MapResourceId,
|
iconResourceId = map.IconResourceId,
|
||||||
centerLatitude = map.MapCenterLatitude,
|
centerLatitude = map.MapCenterLatitude,
|
||||||
centerLongitude = map.MapCenterLongitude,
|
centerLongitude = map.MapCenterLongitude,
|
||||||
categories = map.MapCategories,
|
categories = map.MapCategories,
|
||||||
|
|||||||
@ -243,10 +243,17 @@ namespace ManagerService
|
|||||||
services.AddScoped<SectionIndexingInterceptor>();
|
services.AddScoped<SectionIndexingInterceptor>();
|
||||||
|
|
||||||
services.AddDbContext<MyInfoMateDbContext>((serviceProvider, options) =>
|
services.AddDbContext<MyInfoMateDbContext>((serviceProvider, options) =>
|
||||||
|
{
|
||||||
options.UseNpgsql(dataSource, o => o.UseNetTopologySuite().UseVector())
|
options.UseNpgsql(dataSource, o => o.UseNetTopologySuite().UseVector())
|
||||||
.AddInterceptors(serviceProvider.GetRequiredService<SectionIndexingInterceptor>())
|
.AddInterceptors(serviceProvider.GetRequiredService<SectionIndexingInterceptor>());
|
||||||
.EnableSensitiveDataLogging()
|
#if DEBUG
|
||||||
.LogTo(Console.WriteLine, LogLevel.Information)
|
// Écrit les valeurs des paramètres dans les logs : mots de passe hashés,
|
||||||
|
// clés API, données de visiteurs. Jamais en production — le Dockerfile
|
||||||
|
// publie en `-c Release`, donc ce bloc n'y est pas compilé.
|
||||||
|
options.EnableSensitiveDataLogging()
|
||||||
|
.LogTo(Console.WriteLine, LogLevel.Information);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
services.AddHealthChecks()
|
services.AddHealthChecks()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user