diff --git a/.gitignore b/.gitignore index b13f5b5..30a55a9 100644 --- a/.gitignore +++ b/.gitignore @@ -459,4 +459,6 @@ src/emailpaywall.client/.svelte-kit # Include example tfvars files !**/*.tfvars.example -!**/terraform.tfvars.example \ No newline at end of file +!**/terraform.tfvars.example + +**/appsettings.Development.json \ No newline at end of file diff --git a/deploy/Terraform/container-app.tf b/deploy/Terraform/container-app.tf index 1d873af..ceba8de 100644 --- a/deploy/Terraform/container-app.tf +++ b/deploy/Terraform/container-app.tf @@ -82,7 +82,7 @@ resource "azurerm_container_app" "app" { server = azurerm_container_registry.acr.login_server identity = azurerm_user_assigned_identity.uami.id } - + depends_on = [azurerm_role_assignment.acr_pull, azurerm_mssql_database.db] # needed for container app to access other Microsoft Entra protected resources @@ -179,6 +179,16 @@ resource "azurerm_container_app" "app" { name = "ASPNETCORE_ENVIRONMENT" value = "Production" } + + env { + name = "AzureAIFoundry__ContentSafetyKey" + secret_name = "content-safety-key" + } + + env { + name = "AzureAIFoundry__ContentSafetyEndpoint" + value = var.content_safety_api + } } } @@ -216,4 +226,9 @@ resource "azurerm_container_app" "app" { value = var.smtp_password } + secret { + name = "content-safety-key" + value = var.content_safety_key + } + } \ No newline at end of file diff --git a/deploy/Terraform/variables.tf b/deploy/Terraform/variables.tf index 2c1f847..b53efd6 100644 --- a/deploy/Terraform/variables.tf +++ b/deploy/Terraform/variables.tf @@ -35,3 +35,14 @@ variable "smtp_password" { type = string sensitive = true } + +variable "content_safety_key" { + description = "Azure AI foundry content safety key" + type = string + sensitive = true +} + +variable "content_safety_api" { + description = "Azure AI foundry content safety api endpoint" + type = string +} \ No newline at end of file diff --git a/src/Evently.Server/Common/Domains/Interfaces/IObjectStorageService.cs b/src/Evently.Server/Common/Domains/Interfaces/IObjectStorageService.cs index 7b853c2..2763b08 100644 --- a/src/Evently.Server/Common/Domains/Interfaces/IObjectStorageService.cs +++ b/src/Evently.Server/Common/Domains/Interfaces/IObjectStorageService.cs @@ -10,4 +10,5 @@ public interface IObjectStorageService { Task GetFileUri(string containerName, string fileName); Task GetFile(string containerName, string fileName); Task IsFileExists(string containerName, string fileName); + Task PassesContentModeration(BinaryData binaryData); } \ No newline at end of file diff --git a/src/Evently.Server/Common/Domains/Models/Settings.cs b/src/Evently.Server/Common/Domains/Models/Settings.cs index dee66e8..75348cf 100644 --- a/src/Evently.Server/Common/Domains/Models/Settings.cs +++ b/src/Evently.Server/Common/Domains/Models/Settings.cs @@ -9,6 +9,7 @@ public sealed class Settings { [NotMapped] public AuthSetting Authentication { get; init; } = new(); [NotMapped] public EmailSettings EmailSettings { get; init; } = new(); + [NotMapped] public AzureAIFoundry AzureAiFoundry { get; init; } = new(); } [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")] @@ -32,4 +33,9 @@ public sealed class OAuthSetting { public sealed class EmailSettings { public string ActualFrom { get; init; } = string.Empty; public string SmtpPassword { get; init; } = string.Empty; +} + +public sealed class AzureAIFoundry { + public string ContentSafetyKey { get; init; } = string.Empty; + public string ContentSafetyEndpoint { get; init; } = string.Empty; } \ No newline at end of file diff --git a/src/Evently.Server/Common/Extensions/LoggerExtension.cs b/src/Evently.Server/Common/Extensions/LoggerExtension.cs index a0a0364..56f6a79 100644 --- a/src/Evently.Server/Common/Extensions/LoggerExtension.cs +++ b/src/Evently.Server/Common/Extensions/LoggerExtension.cs @@ -28,4 +28,12 @@ public static partial void LogSuccessEmail( Message = "Error occurred at {context}: {errorMsg}")] public static partial void LogErrorContext( this ILogger logger, string context, string errorMsg); + + [LoggerMessage( + EventId = 5, + Level = LogLevel.Error, + Message = "Analyze image failed. Status code: {statusCode}, Error code: {errorCode}, Error message: {errMsg}")] + public static partial void LogContentModerationError( + this ILogger logger, string statusCode, string errorCode, string errMsg); + // } \ No newline at end of file diff --git a/src/Evently.Server/Evently.Server.csproj b/src/Evently.Server/Evently.Server.csproj index 1828492..839adac 100644 --- a/src/Evently.Server/Evently.Server.csproj +++ b/src/Evently.Server/Evently.Server.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Evently.Server/Features/Files/Services/ObjectStorageService.cs b/src/Evently.Server/Features/Files/Services/ObjectStorageService.cs index 6d5033e..285c02b 100644 --- a/src/Evently.Server/Features/Files/Services/ObjectStorageService.cs +++ b/src/Evently.Server/Features/Files/Services/ObjectStorageService.cs @@ -1,8 +1,10 @@ using Azure; +using Azure.AI.ContentSafety; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Evently.Server.Common.Domains.Interfaces; using Evently.Server.Common.Domains.Models; +using Evently.Server.Common.Extensions; using Microsoft.Extensions.Options; namespace Evently.Server.Features.Files.Services; @@ -11,6 +13,9 @@ namespace Evently.Server.Features.Files.Services; public sealed class ObjectStorageService(IOptions settings, ILogger logger) : IObjectStorageService { private readonly BlobServiceClient _blobServiceClient = new(settings.Value.StorageAccount.AzureStorageConnectionString); + private readonly ContentSafetyClient _contentSafetyClient = new( + endpoint: new Uri(settings.Value.AzureAiFoundry.ContentSafetyEndpoint), + credential: new AzureKeyCredential(settings.Value.AzureAiFoundry.ContentSafetyKey)); public async Task UploadFile(string containerName, string fileName, BinaryData binaryData, string mimeType = "application/octet-stream") { @@ -65,4 +70,23 @@ public async Task GetFile(string containerName, string fileName) { BinaryData data = BinaryData.FromBytes(bytes); return data; } + + public async Task PassesContentModeration(BinaryData binaryData) { + ContentSafetyImageData image = new(binaryData); + AnalyzeImageOptions request = new(image); + Response response; + try { + response = await _contentSafetyClient.AnalyzeImageAsync(request); + } catch (RequestFailedException ex) { + logger.LogContentModerationError(ex.Status.ToString(), ex.ErrorCode ?? "", ex.Message); + throw; + } + + AnalyzeImageResult result = response.Value; + int? score = result.CategoriesAnalysis + .Select(v => v.Severity) + .Aggregate((a, b) => a + b) + ?? 0; + return score == 0; + } } \ No newline at end of file diff --git a/src/Evently.Server/Features/Gatherings/Controllers/GatheringsController.cs b/src/Evently.Server/Features/Gatherings/Controllers/GatheringsController.cs index 420004b..20c0a88 100644 --- a/src/Evently.Server/Features/Gatherings/Controllers/GatheringsController.cs +++ b/src/Evently.Server/Features/Gatherings/Controllers/GatheringsController.cs @@ -68,8 +68,8 @@ public async Task> CreateGathering([FromForm] GatheringR } if (coverImg != null) { - Uri uri = await UploadCoverImage(gatheringReqDto.GatheringId, coverImg: coverImg ?? throw new ArgumentNullException(nameof(coverImg))); - gatheringReqDto = gatheringReqDto with { CoverSrc = uri.AbsoluteUri }; + string uri = await UploadCoverImage(gatheringReqDto.GatheringId, coverImg); + gatheringReqDto = gatheringReqDto with { CoverSrc = uri }; } Gathering gathering = await gatheringService.CreateGathering(gatheringReqDto); @@ -88,9 +88,8 @@ public async Task UpdateGathering(long gatheringId, [FromForm] Gat } if (coverImg != null) { - Uri uri = await UploadCoverImage(gatheringReqDto.GatheringId, coverImg); - gathering.CoverSrc = uri.AbsoluteUri; - gatheringReqDto = gatheringReqDto with { CoverSrc = uri.AbsoluteUri }; + string uri = await UploadCoverImage(gatheringReqDto.GatheringId, coverImg); + gatheringReqDto = gatheringReqDto with { CoverSrc = uri }; } gathering = await gatheringService.UpdateGathering(gatheringId, gatheringReqDto); @@ -112,12 +111,17 @@ public async Task> DeleteGathering(long gatheringId) { return NoContent(); } - private async Task UploadCoverImage(long gatheringId, IFormFile coverImg) { + private async Task UploadCoverImage(long gatheringId, IFormFile coverImg) { string fileName = $"gatherings/{gatheringId}/cover-image{Path.GetExtension(coverImg.FileName)}"; BinaryData binaryData = await coverImg.ToBinaryData(); - return await objectStorageService.UploadFile(_containerName, + bool isContentSafe = await objectStorageService.PassesContentModeration(binaryData); + if (!isContentSafe) { + return string.Empty; + } + Uri uri = await objectStorageService.UploadFile(_containerName, fileName, binaryData, mimeType: MimeTypes.GetMimeType(coverImg.FileName)); + return uri.AbsoluteUri; } } \ No newline at end of file diff --git a/src/Evently.Server/appsettings.Development.json b/src/Evently.Server/appsettings.Development.json deleted file mode 100644 index 0320633..0000000 --- a/src/Evently.Server/appsettings.Development.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*", - "ConnectionStrings": { - "WebApiDatabase": "Data Source=(localdb)\\MSSQLLocalDB;Database=evently;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Application Name=\"SQL Server Management Studio\";Command Timeout=0;" - }, - "StorageAccount": { - "AccountName": "evently-dev-images", - "AzureStorageConnectionString": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;" - }, - "Authentication": { - "Google": { - "ClientId": "", - "ClientSecret": "" - } - }, - "EmailSettings": { - "ActualFrom": "", - "SmtpPassword": "" - } -} diff --git a/src/Evently.Server/appsettings.json b/src/Evently.Server/appsettings.json index 10f68b8..ac76a29 100644 --- a/src/Evently.Server/appsettings.json +++ b/src/Evently.Server/appsettings.json @@ -5,5 +5,26 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + "WebApiDatabase": "Data Source=(localdb)\\MSSQLLocalDB;Database=evently;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Application Name=\"SQL Server Management Studio\";Command Timeout=0;" + }, + "StorageAccount": { + "AccountName": "evently-dev-images", + "AzureStorageConnectionString": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;" + }, + "AzureAIFoundry": { + "ContentSafetyKey": "", + "ContentSafetyEndpoint": "" + }, + "Authentication": { + "Google": { + "ClientId": "", + "ClientSecret": "" + } + }, + "EmailSettings": { + "ActualFrom": "", + "SmtpPassword": "" + } } diff --git a/src/evently.client/src/lib/components/card.tsx b/src/evently.client/src/lib/components/card.tsx index 291e4b8..512083f 100644 --- a/src/evently.client/src/lib/components/card.tsx +++ b/src/evently.client/src/lib/components/card.tsx @@ -18,9 +18,10 @@ export function Card({ gathering, accountId }: CardProps): JSX.Element { (detail) => detail.category ); - // ignore img-src for now - const hash: number = hashString(gathering.name); - imgSrc = hash % 2 === 0 ? Placeholder1 : Placeholder2; + if (imgSrc == null || imgSrc.length === 0) { + const hash: number = hashString(gathering.name); + imgSrc = hash % 2 === 0 ? Placeholder1 : Placeholder2; + } if (title.length > 30) { title = title.substring(0, 30) + "..."; diff --git a/src/evently.client/src/lib/services/gathering-service.ts b/src/evently.client/src/lib/services/gathering-service.ts index 662a1e0..f5efec2 100644 --- a/src/evently.client/src/lib/services/gathering-service.ts +++ b/src/evently.client/src/lib/services/gathering-service.ts @@ -75,7 +75,11 @@ function toFormData(gatheringDto: GatheringReqDto, coverImg?: File | null): Form formData.set(key, value); } } + formData.delete("gatheringCategoryDetails"); + if (gatheringDto.gatheringCategoryDetails.length === 0) { + formData.set("gatheringCategoryDetails", "[]"); + } for (let i = 0; i < gatheringDto.gatheringCategoryDetails.length; i++) { const detail: GatheringCategoryDetailReqDto = gatheringDto.gatheringCategoryDetails[i]; diff --git a/src/evently.client/src/routeTree.gen.ts b/src/evently.client/src/routeTree.gen.ts index 2b5ff9a..038453e 100644 --- a/src/evently.client/src/routeTree.gen.ts +++ b/src/evently.client/src/routeTree.gen.ts @@ -8,301 +8,304 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { Route as rootRouteImport } from "./routes/__root"; -import { Route as IndexRouteImport } from "./routes/index"; -import { Route as LoginIndexRouteImport } from "./routes/login/index"; -import { Route as HealthcheckIndexRouteImport } from "./routes/healthcheck/index"; -import { Route as GatheringsIndexRouteImport } from "./routes/gatherings/index"; -import { Route as BookingsauthRouteRouteImport } from "./routes/bookings/(auth)/route"; -import { Route as GatheringsGatheringIdIndexRouteImport } from "./routes/gatherings/$gatheringId/index"; -import { Route as GatheringsauthCreateRouteImport } from "./routes/gatherings/(auth).create"; -import { Route as BookingsauthHostingIndexRouteImport } from "./routes/bookings/(auth)/hosting/index"; -import { Route as BookingsauthAttendingIndexRouteImport } from "./routes/bookings/(auth)/attending/index"; -import { Route as GatheringsGatheringIdauthUpdateRouteImport } from "./routes/gatherings/$gatheringId/(auth).update"; -import { Route as BookingsauthHostingGatheringIdDashboardIndexRouteImport } from "./routes/bookings/(auth)/hosting/$gatheringId/dashboard.index"; -import { Route as BookingsauthHostingGatheringIdDashboardScanRouteImport } from "./routes/bookings/(auth)/hosting/$gatheringId/dashboard.scan"; +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' +import { Route as LoginIndexRouteImport } from './routes/login/index' +import { Route as HealthcheckIndexRouteImport } from './routes/healthcheck/index' +import { Route as GatheringsIndexRouteImport } from './routes/gatherings/index' +import { Route as BookingsauthRouteRouteImport } from './routes/bookings/(auth)/route' +import { Route as GatheringsGatheringIdIndexRouteImport } from './routes/gatherings/$gatheringId/index' +import { Route as GatheringsauthCreateRouteImport } from './routes/gatherings/(auth).create' +import { Route as BookingsauthHostingIndexRouteImport } from './routes/bookings/(auth)/hosting/index' +import { Route as BookingsauthAttendingIndexRouteImport } from './routes/bookings/(auth)/attending/index' +import { Route as GatheringsGatheringIdauthUpdateRouteImport } from './routes/gatherings/$gatheringId/(auth).update' +import { Route as BookingsauthHostingGatheringIdDashboardIndexRouteImport } from './routes/bookings/(auth)/hosting/$gatheringId/dashboard.index' +import { Route as BookingsauthHostingGatheringIdDashboardScanRouteImport } from './routes/bookings/(auth)/hosting/$gatheringId/dashboard.scan' const IndexRoute = IndexRouteImport.update({ - id: "/", - path: "/", - getParentRoute: () => rootRouteImport -} as any); + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) const LoginIndexRoute = LoginIndexRouteImport.update({ - id: "/login/", - path: "/login/", - getParentRoute: () => rootRouteImport -} as any); + id: '/login/', + path: '/login/', + getParentRoute: () => rootRouteImport, +} as any) const HealthcheckIndexRoute = HealthcheckIndexRouteImport.update({ - id: "/healthcheck/", - path: "/healthcheck/", - getParentRoute: () => rootRouteImport -} as any); + id: '/healthcheck/', + path: '/healthcheck/', + getParentRoute: () => rootRouteImport, +} as any) const GatheringsIndexRoute = GatheringsIndexRouteImport.update({ - id: "/gatherings/", - path: "/gatherings/", - getParentRoute: () => rootRouteImport -} as any); + id: '/gatherings/', + path: '/gatherings/', + getParentRoute: () => rootRouteImport, +} as any) const BookingsauthRouteRoute = BookingsauthRouteRouteImport.update({ - id: "/bookings/(auth)", - path: "/bookings/", - getParentRoute: () => rootRouteImport -} as any); -const GatheringsGatheringIdIndexRoute = GatheringsGatheringIdIndexRouteImport.update({ - id: "/gatherings/$gatheringId/", - path: "/gatherings/$gatheringId/", - getParentRoute: () => rootRouteImport -} as any); + id: '/bookings/(auth)', + path: '/bookings/', + getParentRoute: () => rootRouteImport, +} as any) +const GatheringsGatheringIdIndexRoute = + GatheringsGatheringIdIndexRouteImport.update({ + id: '/gatherings/$gatheringId/', + path: '/gatherings/$gatheringId/', + getParentRoute: () => rootRouteImport, + } as any) const GatheringsauthCreateRoute = GatheringsauthCreateRouteImport.update({ - id: "/gatherings/(auth)/create", - path: "/gatherings/create", - getParentRoute: () => rootRouteImport -} as any); -const BookingsauthHostingIndexRoute = BookingsauthHostingIndexRouteImport.update({ - id: "/hosting/", - path: "/hosting/", - getParentRoute: () => BookingsauthRouteRoute -} as any); -const BookingsauthAttendingIndexRoute = BookingsauthAttendingIndexRouteImport.update({ - id: "/attending/", - path: "/attending/", - getParentRoute: () => BookingsauthRouteRoute -} as any); -const GatheringsGatheringIdauthUpdateRoute = GatheringsGatheringIdauthUpdateRouteImport.update({ - id: "/gatherings/$gatheringId/(auth)/update", - path: "/gatherings/$gatheringId/update", - getParentRoute: () => rootRouteImport -} as any); + id: '/gatherings/(auth)/create', + path: '/gatherings/create', + getParentRoute: () => rootRouteImport, +} as any) +const BookingsauthHostingIndexRoute = + BookingsauthHostingIndexRouteImport.update({ + id: '/hosting/', + path: '/hosting/', + getParentRoute: () => BookingsauthRouteRoute, + } as any) +const BookingsauthAttendingIndexRoute = + BookingsauthAttendingIndexRouteImport.update({ + id: '/attending/', + path: '/attending/', + getParentRoute: () => BookingsauthRouteRoute, + } as any) +const GatheringsGatheringIdauthUpdateRoute = + GatheringsGatheringIdauthUpdateRouteImport.update({ + id: '/gatherings/$gatheringId/(auth)/update', + path: '/gatherings/$gatheringId/update', + getParentRoute: () => rootRouteImport, + } as any) const BookingsauthHostingGatheringIdDashboardIndexRoute = - BookingsauthHostingGatheringIdDashboardIndexRouteImport.update({ - id: "/hosting/$gatheringId/dashboard/", - path: "/hosting/$gatheringId/dashboard/", - getParentRoute: () => BookingsauthRouteRoute - } as any); + BookingsauthHostingGatheringIdDashboardIndexRouteImport.update({ + id: '/hosting/$gatheringId/dashboard/', + path: '/hosting/$gatheringId/dashboard/', + getParentRoute: () => BookingsauthRouteRoute, + } as any) const BookingsauthHostingGatheringIdDashboardScanRoute = - BookingsauthHostingGatheringIdDashboardScanRouteImport.update({ - id: "/hosting/$gatheringId/dashboard/scan", - path: "/hosting/$gatheringId/dashboard/scan", - getParentRoute: () => BookingsauthRouteRoute - } as any); + BookingsauthHostingGatheringIdDashboardScanRouteImport.update({ + id: '/hosting/$gatheringId/dashboard/scan', + path: '/hosting/$gatheringId/dashboard/scan', + getParentRoute: () => BookingsauthRouteRoute, + } as any) export interface FileRoutesByFullPath { - "/": typeof IndexRoute; - "/bookings": typeof BookingsauthRouteRouteWithChildren; - "/gatherings": typeof GatheringsIndexRoute; - "/healthcheck": typeof HealthcheckIndexRoute; - "/login": typeof LoginIndexRoute; - "/gatherings/create": typeof GatheringsauthCreateRoute; - "/gatherings/$gatheringId": typeof GatheringsGatheringIdIndexRoute; - "/gatherings/$gatheringId/update": typeof GatheringsGatheringIdauthUpdateRoute; - "/bookings/attending": typeof BookingsauthAttendingIndexRoute; - "/bookings/hosting": typeof BookingsauthHostingIndexRoute; - "/bookings/hosting/$gatheringId/dashboard/scan": typeof BookingsauthHostingGatheringIdDashboardScanRoute; - "/bookings/hosting/$gatheringId/dashboard": typeof BookingsauthHostingGatheringIdDashboardIndexRoute; + '/': typeof IndexRoute + '/bookings': typeof BookingsauthRouteRouteWithChildren + '/gatherings': typeof GatheringsIndexRoute + '/healthcheck': typeof HealthcheckIndexRoute + '/login': typeof LoginIndexRoute + '/gatherings/create': typeof GatheringsauthCreateRoute + '/gatherings/$gatheringId': typeof GatheringsGatheringIdIndexRoute + '/gatherings/$gatheringId/update': typeof GatheringsGatheringIdauthUpdateRoute + '/bookings/attending': typeof BookingsauthAttendingIndexRoute + '/bookings/hosting': typeof BookingsauthHostingIndexRoute + '/bookings/hosting/$gatheringId/dashboard/scan': typeof BookingsauthHostingGatheringIdDashboardScanRoute + '/bookings/hosting/$gatheringId/dashboard': typeof BookingsauthHostingGatheringIdDashboardIndexRoute } export interface FileRoutesByTo { - "/": typeof IndexRoute; - "/bookings": typeof BookingsauthRouteRouteWithChildren; - "/gatherings": typeof GatheringsIndexRoute; - "/healthcheck": typeof HealthcheckIndexRoute; - "/login": typeof LoginIndexRoute; - "/gatherings/create": typeof GatheringsauthCreateRoute; - "/gatherings/$gatheringId": typeof GatheringsGatheringIdIndexRoute; - "/gatherings/$gatheringId/update": typeof GatheringsGatheringIdauthUpdateRoute; - "/bookings/attending": typeof BookingsauthAttendingIndexRoute; - "/bookings/hosting": typeof BookingsauthHostingIndexRoute; - "/bookings/hosting/$gatheringId/dashboard/scan": typeof BookingsauthHostingGatheringIdDashboardScanRoute; - "/bookings/hosting/$gatheringId/dashboard": typeof BookingsauthHostingGatheringIdDashboardIndexRoute; + '/': typeof IndexRoute + '/bookings': typeof BookingsauthRouteRouteWithChildren + '/gatherings': typeof GatheringsIndexRoute + '/healthcheck': typeof HealthcheckIndexRoute + '/login': typeof LoginIndexRoute + '/gatherings/create': typeof GatheringsauthCreateRoute + '/gatherings/$gatheringId': typeof GatheringsGatheringIdIndexRoute + '/gatherings/$gatheringId/update': typeof GatheringsGatheringIdauthUpdateRoute + '/bookings/attending': typeof BookingsauthAttendingIndexRoute + '/bookings/hosting': typeof BookingsauthHostingIndexRoute + '/bookings/hosting/$gatheringId/dashboard/scan': typeof BookingsauthHostingGatheringIdDashboardScanRoute + '/bookings/hosting/$gatheringId/dashboard': typeof BookingsauthHostingGatheringIdDashboardIndexRoute } export interface FileRoutesById { - __root__: typeof rootRouteImport; - "/": typeof IndexRoute; - "/bookings/(auth)": typeof BookingsauthRouteRouteWithChildren; - "/gatherings/": typeof GatheringsIndexRoute; - "/healthcheck/": typeof HealthcheckIndexRoute; - "/login/": typeof LoginIndexRoute; - "/gatherings/(auth)/create": typeof GatheringsauthCreateRoute; - "/gatherings/$gatheringId/": typeof GatheringsGatheringIdIndexRoute; - "/gatherings/$gatheringId/(auth)/update": typeof GatheringsGatheringIdauthUpdateRoute; - "/bookings/(auth)/attending/": typeof BookingsauthAttendingIndexRoute; - "/bookings/(auth)/hosting/": typeof BookingsauthHostingIndexRoute; - "/bookings/(auth)/hosting/$gatheringId/dashboard/scan": typeof BookingsauthHostingGatheringIdDashboardScanRoute; - "/bookings/(auth)/hosting/$gatheringId/dashboard/": typeof BookingsauthHostingGatheringIdDashboardIndexRoute; + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/bookings/(auth)': typeof BookingsauthRouteRouteWithChildren + '/gatherings/': typeof GatheringsIndexRoute + '/healthcheck/': typeof HealthcheckIndexRoute + '/login/': typeof LoginIndexRoute + '/gatherings/(auth)/create': typeof GatheringsauthCreateRoute + '/gatherings/$gatheringId/': typeof GatheringsGatheringIdIndexRoute + '/gatherings/$gatheringId/(auth)/update': typeof GatheringsGatheringIdauthUpdateRoute + '/bookings/(auth)/attending/': typeof BookingsauthAttendingIndexRoute + '/bookings/(auth)/hosting/': typeof BookingsauthHostingIndexRoute + '/bookings/(auth)/hosting/$gatheringId/dashboard/scan': typeof BookingsauthHostingGatheringIdDashboardScanRoute + '/bookings/(auth)/hosting/$gatheringId/dashboard/': typeof BookingsauthHostingGatheringIdDashboardIndexRoute } export interface FileRouteTypes { - fileRoutesByFullPath: FileRoutesByFullPath; - fullPaths: - | "/" - | "/bookings" - | "/gatherings" - | "/healthcheck" - | "/login" - | "/gatherings/create" - | "/gatherings/$gatheringId" - | "/gatherings/$gatheringId/update" - | "/bookings/attending" - | "/bookings/hosting" - | "/bookings/hosting/$gatheringId/dashboard/scan" - | "/bookings/hosting/$gatheringId/dashboard"; - fileRoutesByTo: FileRoutesByTo; - to: - | "/" - | "/bookings" - | "/gatherings" - | "/healthcheck" - | "/login" - | "/gatherings/create" - | "/gatherings/$gatheringId" - | "/gatherings/$gatheringId/update" - | "/bookings/attending" - | "/bookings/hosting" - | "/bookings/hosting/$gatheringId/dashboard/scan" - | "/bookings/hosting/$gatheringId/dashboard"; - id: - | "__root__" - | "/" - | "/bookings/(auth)" - | "/gatherings/" - | "/healthcheck/" - | "/login/" - | "/gatherings/(auth)/create" - | "/gatherings/$gatheringId/" - | "/gatherings/$gatheringId/(auth)/update" - | "/bookings/(auth)/attending/" - | "/bookings/(auth)/hosting/" - | "/bookings/(auth)/hosting/$gatheringId/dashboard/scan" - | "/bookings/(auth)/hosting/$gatheringId/dashboard/"; - fileRoutesById: FileRoutesById; + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/bookings' + | '/gatherings' + | '/healthcheck' + | '/login' + | '/gatherings/create' + | '/gatherings/$gatheringId' + | '/gatherings/$gatheringId/update' + | '/bookings/attending' + | '/bookings/hosting' + | '/bookings/hosting/$gatheringId/dashboard/scan' + | '/bookings/hosting/$gatheringId/dashboard' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/bookings' + | '/gatherings' + | '/healthcheck' + | '/login' + | '/gatherings/create' + | '/gatherings/$gatheringId' + | '/gatherings/$gatheringId/update' + | '/bookings/attending' + | '/bookings/hosting' + | '/bookings/hosting/$gatheringId/dashboard/scan' + | '/bookings/hosting/$gatheringId/dashboard' + id: + | '__root__' + | '/' + | '/bookings/(auth)' + | '/gatherings/' + | '/healthcheck/' + | '/login/' + | '/gatherings/(auth)/create' + | '/gatherings/$gatheringId/' + | '/gatherings/$gatheringId/(auth)/update' + | '/bookings/(auth)/attending/' + | '/bookings/(auth)/hosting/' + | '/bookings/(auth)/hosting/$gatheringId/dashboard/scan' + | '/bookings/(auth)/hosting/$gatheringId/dashboard/' + fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute; - BookingsauthRouteRoute: typeof BookingsauthRouteRouteWithChildren; - GatheringsIndexRoute: typeof GatheringsIndexRoute; - HealthcheckIndexRoute: typeof HealthcheckIndexRoute; - LoginIndexRoute: typeof LoginIndexRoute; - GatheringsauthCreateRoute: typeof GatheringsauthCreateRoute; - GatheringsGatheringIdIndexRoute: typeof GatheringsGatheringIdIndexRoute; - GatheringsGatheringIdauthUpdateRoute: typeof GatheringsGatheringIdauthUpdateRoute; + IndexRoute: typeof IndexRoute + BookingsauthRouteRoute: typeof BookingsauthRouteRouteWithChildren + GatheringsIndexRoute: typeof GatheringsIndexRoute + HealthcheckIndexRoute: typeof HealthcheckIndexRoute + LoginIndexRoute: typeof LoginIndexRoute + GatheringsauthCreateRoute: typeof GatheringsauthCreateRoute + GatheringsGatheringIdIndexRoute: typeof GatheringsGatheringIdIndexRoute + GatheringsGatheringIdauthUpdateRoute: typeof GatheringsGatheringIdauthUpdateRoute } -declare module "@tanstack/react-router" { - interface FileRoutesByPath { - "/": { - id: "/"; - path: "/"; - fullPath: "/"; - preLoaderRoute: typeof IndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/login/": { - id: "/login/"; - path: "/login"; - fullPath: "/login"; - preLoaderRoute: typeof LoginIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/healthcheck/": { - id: "/healthcheck/"; - path: "/healthcheck"; - fullPath: "/healthcheck"; - preLoaderRoute: typeof HealthcheckIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/gatherings/": { - id: "/gatherings/"; - path: "/gatherings"; - fullPath: "/gatherings"; - preLoaderRoute: typeof GatheringsIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/bookings/(auth)": { - id: "/bookings/(auth)"; - path: "/bookings"; - fullPath: "/bookings"; - preLoaderRoute: typeof BookingsauthRouteRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/gatherings/$gatheringId/": { - id: "/gatherings/$gatheringId/"; - path: "/gatherings/$gatheringId"; - fullPath: "/gatherings/$gatheringId"; - preLoaderRoute: typeof GatheringsGatheringIdIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/gatherings/(auth)/create": { - id: "/gatherings/(auth)/create"; - path: "/gatherings/create"; - fullPath: "/gatherings/create"; - preLoaderRoute: typeof GatheringsauthCreateRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/bookings/(auth)/hosting/": { - id: "/bookings/(auth)/hosting/"; - path: "/hosting"; - fullPath: "/bookings/hosting"; - preLoaderRoute: typeof BookingsauthHostingIndexRouteImport; - parentRoute: typeof BookingsauthRouteRoute; - }; - "/bookings/(auth)/attending/": { - id: "/bookings/(auth)/attending/"; - path: "/attending"; - fullPath: "/bookings/attending"; - preLoaderRoute: typeof BookingsauthAttendingIndexRouteImport; - parentRoute: typeof BookingsauthRouteRoute; - }; - "/gatherings/$gatheringId/(auth)/update": { - id: "/gatherings/$gatheringId/(auth)/update"; - path: "/gatherings/$gatheringId/update"; - fullPath: "/gatherings/$gatheringId/update"; - preLoaderRoute: typeof GatheringsGatheringIdauthUpdateRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/bookings/(auth)/hosting/$gatheringId/dashboard/": { - id: "/bookings/(auth)/hosting/$gatheringId/dashboard/"; - path: "/hosting/$gatheringId/dashboard"; - fullPath: "/bookings/hosting/$gatheringId/dashboard"; - preLoaderRoute: typeof BookingsauthHostingGatheringIdDashboardIndexRouteImport; - parentRoute: typeof BookingsauthRouteRoute; - }; - "/bookings/(auth)/hosting/$gatheringId/dashboard/scan": { - id: "/bookings/(auth)/hosting/$gatheringId/dashboard/scan"; - path: "/hosting/$gatheringId/dashboard/scan"; - fullPath: "/bookings/hosting/$gatheringId/dashboard/scan"; - preLoaderRoute: typeof BookingsauthHostingGatheringIdDashboardScanRouteImport; - parentRoute: typeof BookingsauthRouteRoute; - }; - } +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/login/': { + id: '/login/' + path: '/login' + fullPath: '/login' + preLoaderRoute: typeof LoginIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/healthcheck/': { + id: '/healthcheck/' + path: '/healthcheck' + fullPath: '/healthcheck' + preLoaderRoute: typeof HealthcheckIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/gatherings/': { + id: '/gatherings/' + path: '/gatherings' + fullPath: '/gatherings' + preLoaderRoute: typeof GatheringsIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/bookings/(auth)': { + id: '/bookings/(auth)' + path: '/bookings' + fullPath: '/bookings' + preLoaderRoute: typeof BookingsauthRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/gatherings/$gatheringId/': { + id: '/gatherings/$gatheringId/' + path: '/gatherings/$gatheringId' + fullPath: '/gatherings/$gatheringId' + preLoaderRoute: typeof GatheringsGatheringIdIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/gatherings/(auth)/create': { + id: '/gatherings/(auth)/create' + path: '/gatherings/create' + fullPath: '/gatherings/create' + preLoaderRoute: typeof GatheringsauthCreateRouteImport + parentRoute: typeof rootRouteImport + } + '/bookings/(auth)/hosting/': { + id: '/bookings/(auth)/hosting/' + path: '/hosting' + fullPath: '/bookings/hosting' + preLoaderRoute: typeof BookingsauthHostingIndexRouteImport + parentRoute: typeof BookingsauthRouteRoute + } + '/bookings/(auth)/attending/': { + id: '/bookings/(auth)/attending/' + path: '/attending' + fullPath: '/bookings/attending' + preLoaderRoute: typeof BookingsauthAttendingIndexRouteImport + parentRoute: typeof BookingsauthRouteRoute + } + '/gatherings/$gatheringId/(auth)/update': { + id: '/gatherings/$gatheringId/(auth)/update' + path: '/gatherings/$gatheringId/update' + fullPath: '/gatherings/$gatheringId/update' + preLoaderRoute: typeof GatheringsGatheringIdauthUpdateRouteImport + parentRoute: typeof rootRouteImport + } + '/bookings/(auth)/hosting/$gatheringId/dashboard/': { + id: '/bookings/(auth)/hosting/$gatheringId/dashboard/' + path: '/hosting/$gatheringId/dashboard' + fullPath: '/bookings/hosting/$gatheringId/dashboard' + preLoaderRoute: typeof BookingsauthHostingGatheringIdDashboardIndexRouteImport + parentRoute: typeof BookingsauthRouteRoute + } + '/bookings/(auth)/hosting/$gatheringId/dashboard/scan': { + id: '/bookings/(auth)/hosting/$gatheringId/dashboard/scan' + path: '/hosting/$gatheringId/dashboard/scan' + fullPath: '/bookings/hosting/$gatheringId/dashboard/scan' + preLoaderRoute: typeof BookingsauthHostingGatheringIdDashboardScanRouteImport + parentRoute: typeof BookingsauthRouteRoute + } + } } interface BookingsauthRouteRouteChildren { - BookingsauthAttendingIndexRoute: typeof BookingsauthAttendingIndexRoute; - BookingsauthHostingIndexRoute: typeof BookingsauthHostingIndexRoute; - BookingsauthHostingGatheringIdDashboardScanRoute: typeof BookingsauthHostingGatheringIdDashboardScanRoute; - BookingsauthHostingGatheringIdDashboardIndexRoute: typeof BookingsauthHostingGatheringIdDashboardIndexRoute; + BookingsauthAttendingIndexRoute: typeof BookingsauthAttendingIndexRoute + BookingsauthHostingIndexRoute: typeof BookingsauthHostingIndexRoute + BookingsauthHostingGatheringIdDashboardScanRoute: typeof BookingsauthHostingGatheringIdDashboardScanRoute + BookingsauthHostingGatheringIdDashboardIndexRoute: typeof BookingsauthHostingGatheringIdDashboardIndexRoute } const BookingsauthRouteRouteChildren: BookingsauthRouteRouteChildren = { - BookingsauthAttendingIndexRoute: BookingsauthAttendingIndexRoute, - BookingsauthHostingIndexRoute: BookingsauthHostingIndexRoute, - BookingsauthHostingGatheringIdDashboardScanRoute: - BookingsauthHostingGatheringIdDashboardScanRoute, - BookingsauthHostingGatheringIdDashboardIndexRoute: - BookingsauthHostingGatheringIdDashboardIndexRoute -}; + BookingsauthAttendingIndexRoute: BookingsauthAttendingIndexRoute, + BookingsauthHostingIndexRoute: BookingsauthHostingIndexRoute, + BookingsauthHostingGatheringIdDashboardScanRoute: + BookingsauthHostingGatheringIdDashboardScanRoute, + BookingsauthHostingGatheringIdDashboardIndexRoute: + BookingsauthHostingGatheringIdDashboardIndexRoute, +} -const BookingsauthRouteRouteWithChildren = BookingsauthRouteRoute._addFileChildren( - BookingsauthRouteRouteChildren -); +const BookingsauthRouteRouteWithChildren = + BookingsauthRouteRoute._addFileChildren(BookingsauthRouteRouteChildren) const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, - BookingsauthRouteRoute: BookingsauthRouteRouteWithChildren, - GatheringsIndexRoute: GatheringsIndexRoute, - HealthcheckIndexRoute: HealthcheckIndexRoute, - LoginIndexRoute: LoginIndexRoute, - GatheringsauthCreateRoute: GatheringsauthCreateRoute, - GatheringsGatheringIdIndexRoute: GatheringsGatheringIdIndexRoute, - GatheringsGatheringIdauthUpdateRoute: GatheringsGatheringIdauthUpdateRoute -}; + IndexRoute: IndexRoute, + BookingsauthRouteRoute: BookingsauthRouteRouteWithChildren, + GatheringsIndexRoute: GatheringsIndexRoute, + HealthcheckIndexRoute: HealthcheckIndexRoute, + LoginIndexRoute: LoginIndexRoute, + GatheringsauthCreateRoute: GatheringsauthCreateRoute, + GatheringsGatheringIdIndexRoute: GatheringsGatheringIdIndexRoute, + GatheringsGatheringIdauthUpdateRoute: GatheringsGatheringIdauthUpdateRoute, +} export const routeTree = rootRouteImport - ._addFileChildren(rootRouteChildren) - ._addFileTypes(); + ._addFileChildren(rootRouteChildren) + ._addFileTypes()