Securite
- RequireAppKey : filtre qui exige une cle d'API valide ou un utilisateur du
manager. Pose sur les routes de contenu consommees par les apps visiteur
(Configuration, Section, Resource, SectionMap, SectionEvent, SectionAgenda,
SectionParcours, SectionQuiz, ApplicationInstance). Un [Authorize] d'action
ne peut pas assouplir celui de la classe ; seul [AllowAnonymous] le
court-circuite, et le filtre redevient le controle d'acces. Il ferme
l'enumeration par identifiant, pas la confidentialite : la cle s'obtient
par le slug ou le pincode.
- Instance/slug/{slug} rendait le pinCode, l'adresse de facturation, la TVA et
les quotas a qui lit l'URL du site visiteur. StripCommercialFields est
desormais applique sur slug et byPin ; isTrialActive reste expose pour le
filigrane d'essai.
- Device.Create et Device/{id}/detail repondaient 403 a toute tablette depuis
a452f4a (13/03) : la classe exige InstanceAdmin, une cle ne porte que
AppRead. Ouverts a la cle, le cloisonnement par instance etait deja ecrit.
Canal VR
- Device.AppType (defaut Tablet, backfill a 1) ; Create resout
l'ApplicationInstance sur ce type au lieu de Tablet en dur.
- Get filtre optionnellement par appType ; DeviceDetailDTO expose appVersion
et lastSeen.
- PUT Device/{id}/heartbeat : batterie, version, connexion. Volontairement
etroit, une app ne peut ni se renommer ni changer d'instance.
- ApiKeyAppType.VrApp en fin d'enum.
Contenu immersif
- ResourceType : Image360 (11), Video360 (12), Model3D (13), en fin d'enum.
- Section Scene3D : un modele GLB et ses points d'interet, en objet manipule
ou en decor habite. Les points sont des GeoPoint, avec une LocalTransform
en jsonb (convention glTF) ; CRUD dans SectionScene3DController.
- Instance.HasImmersiveContent : l'add-on ajoute 100 Go au quota de stockage,
repose apres un changement de plan et retire a la desactivation.
- ImmersiveBackground (owned) sur Configuration et ApplicationInstance, avec
une image de repli pour les canaux qui ne rendent pas l'immersif.
Export de configuration
- exportVersion (1) et generatedAt : le JSON devient un contrat, lu tel quel
par l'app Unity.
- Section.ToDTO() n'etant pas virtuelle, l'export ne portait aucun champ
specifique de sous-type. Passe par SectionFactory.ToDTO, et charge les
points des Map et des Scene3D.
- Le fond immersif et son repli partent avec les ressources, URL resolues.
Migrations : AddAppTypeToDevice, AddScene3DSectionAndImmersiveAddon,
AddImmersiveBackground.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
140 lines
5.0 KiB
C#
140 lines
5.0 KiB
C#
using Manager.DTOs;
|
|
using ManagerService.Data.SubSection;
|
|
using ManagerService.DTOs;
|
|
using ManagerService.Services;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
using System.Linq;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace ManagerService.Data
|
|
{
|
|
/// <summary>
|
|
/// Defines the link between an application instance and a configuration,
|
|
/// allowing apps to use one or multiple configurations.
|
|
/// </summary>
|
|
[Index(nameof(InstanceId))]
|
|
[Index(nameof(InstanceId), nameof(AppType), IsUnique = true)]
|
|
public class ApplicationInstance : IAuditableEntity
|
|
{
|
|
[Key]
|
|
public string Id { get; set; }
|
|
|
|
[Required]
|
|
public string InstanceId { get; set; }
|
|
|
|
public DateTime DateCreation { get; set; }
|
|
|
|
public DateTime DateUpdate { get; set; }
|
|
|
|
[Required]
|
|
public AppType AppType { get; set; }
|
|
|
|
public List<AppConfigurationLink> Configurations { get; set; }
|
|
|
|
public string MainImageId { get; set; } // Specific Mobile et web(?)
|
|
|
|
public string MainImageUrl { get; set; } // Specific Mobile et web(?)
|
|
|
|
public string LoaderImageId { get; set; } // Specific Mobile et web
|
|
|
|
public string LoaderImageUrl { get; set; } // Specific Mobile et web
|
|
|
|
public string PrimaryColor { get; set; } // Specific Mobile et web
|
|
|
|
public string SecondaryColor { get; set; } // Specific Mobile et web
|
|
|
|
public List<string> Languages { get; set; } // All app must support languages, if not, client's problem
|
|
|
|
public string? SectionEventId { get; set; } // Specific Mobile et web(?)
|
|
[ForeignKey("SectionEventId")]
|
|
public SectionEvent? SectionEvent { get; set; } // => To Display in large a event with countdown (in mobile app).
|
|
|
|
public bool IsAssistant { get; set; } = false;
|
|
|
|
public bool IsQRCodeEnabled { get; set; } = true;
|
|
|
|
public List<TranslationDTO>? AppName { get; set; } // Specific Mobile et web
|
|
|
|
// Chaque client a sa propre app publiée par Unov : seul un SuperAdmin les modifie.
|
|
public string? AppStoreUrl { get; set; } // Specific Mobile
|
|
|
|
public string? PlayStoreUrl { get; set; } // Specific Mobile
|
|
|
|
/// <summary>
|
|
/// Fond du menu général — spécifique VR. C'est le pendant immersif de
|
|
/// <c>MainImageId</c> : sans lui, le menu du casque flotte dans le noir.
|
|
/// </summary>
|
|
public ImmersiveBackground? ImmersiveBackground { get; set; }
|
|
|
|
public ApplicationInstanceDTO ToDTO(MyInfoMateDbContext myInfoMateDbContext)
|
|
{
|
|
SectionEventDTO sectionEventDTO = null;
|
|
|
|
if (SectionEventId != null)
|
|
{
|
|
SectionEvent = myInfoMateDbContext.Sections.OfType<SectionEvent>().FirstOrDefault(s => s.Id == SectionEventId);
|
|
sectionEventDTO = SectionEvent != null ? SectionFactory.ToDTO(SectionEvent) as SectionEventDTO : null;
|
|
}
|
|
|
|
return new ApplicationInstanceDTO()
|
|
{
|
|
id = Id,
|
|
instanceId = InstanceId,
|
|
appType = AppType,
|
|
configurations = Configurations,
|
|
mainImageId = MainImageId,
|
|
mainImageUrl = MainImageUrl,
|
|
loaderImageId = LoaderImageId,
|
|
loaderImageUrl = LoaderImageUrl,
|
|
primaryColor = PrimaryColor,
|
|
secondaryColor = SecondaryColor,
|
|
languages = Languages,
|
|
sectionEventId = SectionEventId,
|
|
sectionEventDTO = sectionEventDTO,
|
|
isAssistant = IsAssistant,
|
|
isQRCodeEnabled = IsQRCodeEnabled,
|
|
appName = AppName,
|
|
appStoreUrl = AppStoreUrl,
|
|
playStoreUrl = PlayStoreUrl,
|
|
immersiveBackground = ImmersiveBackground?.ToDTO()
|
|
};
|
|
}
|
|
|
|
public ApplicationInstance FromDTO(ApplicationInstanceDTO dto)
|
|
{
|
|
InstanceId = dto.instanceId;
|
|
AppType = dto.appType;
|
|
MainImageId = dto.mainImageId;
|
|
MainImageUrl = dto.mainImageUrl;
|
|
LoaderImageId = dto.loaderImageId;
|
|
LoaderImageUrl = dto.loaderImageUrl;
|
|
PrimaryColor = dto.primaryColor;
|
|
SecondaryColor = dto.secondaryColor;
|
|
Languages = dto.languages;
|
|
Configurations = dto.configurations;
|
|
SectionEventId = dto.sectionEventId;
|
|
IsAssistant = dto.isAssistant;
|
|
IsQRCodeEnabled = dto.isQRCodeEnabled;
|
|
AppName = dto.appName;
|
|
AppStoreUrl = dto.appStoreUrl;
|
|
PlayStoreUrl = dto.playStoreUrl;
|
|
ImmersiveBackground = Data.ImmersiveBackground.FromDTO(dto.immersiveBackground);
|
|
|
|
return this;
|
|
}
|
|
|
|
}
|
|
|
|
public enum AppType
|
|
{
|
|
Mobile,
|
|
Tablet,
|
|
Web,
|
|
VR,
|
|
Voice // Lunettes Ray-Ban Meta / interface vocale — pas de navigation UI
|
|
}
|
|
}
|