From d2d5daf2d8b49c9dd32a0733f27d85de6e7bad96 Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Mon, 5 Nov 2018 10:45:38 +0100
Subject: [PATCH 1/8] Adding Base Controller & [cid] literal for routing

---
 .../Controllers/AnnouncementsController.cs          |  4 ++--
 .../Controllers/ArtShowController.cs                |  4 ++--
 .../Controllers/BaseController.cs                   | 10 ++++++++++
 .../Controllers/CommunicationController.cs          |  4 ++--
 .../Controllers/DealersController.cs                |  4 ++--
 .../Controllers/EventConferenceDaysController.cs    |  4 ++--
 .../Controllers/EventConferenceRoomsController.cs   |  4 ++--
 .../Controllers/EventConferenceTracksController.cs  |  4 ++--
 .../Controllers/EventFeedbackController.cs          |  4 ++--
 .../Controllers/EventsController.cs                 |  4 ++--
 .../Controllers/FursuitsController.cs               |  4 ++--
 .../Controllers/ImagesController.cs                 |  4 ++--
 .../Controllers/KnowledgeEntriesController.cs       |  4 ++--
 .../Controllers/KnowledgeGroupsController.cs        |  4 ++--
 .../Controllers/MapsController.cs                   |  4 ++--
 .../Controllers/PushNotificationsController.cs      |  4 ++--
 .../Controllers/RichPreviewController.cs            |  2 +-
 .../Controllers/SyncController.cs                   |  4 ++--
 .../Controllers/TokensController.cs                 |  4 ++--
 .../Extensions/CidRouteValueProvider.cs             | 13 +++++++++++++
 20 files changed, 58 insertions(+), 35 deletions(-)
 create mode 100644 src/Eurofurence.App.Server.Web/Controllers/BaseController.cs
 create mode 100644 src/Eurofurence.App.Server.Web/Extensions/CidRouteValueProvider.cs

diff --git a/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs b/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs
index 0c5fa7d6..d84ccdc2 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs
@@ -10,8 +10,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class AnnouncementsController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class AnnouncementsController : BaseController
     {
         private readonly IAnnouncementService _announcementService;
         private readonly IPushEventMediator _eventMediator;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs b/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
index 6852440f..58bd02c6 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
@@ -13,8 +13,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class ArtShowController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class ArtShowController : BaseController
     {
         private readonly IItemActivityService _itemActivityService;
         private readonly IApiPrincipal _apiPrincipal;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/BaseController.cs b/src/Eurofurence.App.Server.Web/Controllers/BaseController.cs
new file mode 100644
index 00000000..0cd0caab
--- /dev/null
+++ b/src/Eurofurence.App.Server.Web/Controllers/BaseController.cs
@@ -0,0 +1,10 @@
+using Eurofurence.App.Server.Web.Extensions;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Eurofurence.App.Server.Web.Controllers
+{
+    [CidRouteBase]
+    public class BaseController : Controller
+    {
+    }
+}
diff --git a/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs b/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
index 2b71cacf..03152a80 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
@@ -11,8 +11,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class CommunicationController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class CommunicationController : BaseController
     {
         private readonly IApiPrincipal _apiPrincipal;
         private readonly IPrivateMessageService _privateMessageService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs b/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs
index fd93faa3..dc26cf8f 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs
@@ -8,8 +8,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class DealersController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class DealersController : BaseController
     {
         private readonly IDealerService _dealerService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs
index 6b4cc0c4..3a1acfa9 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs
@@ -8,8 +8,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class EventConferenceDaysController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class EventConferenceDaysController : BaseController
     {
         private readonly IEventConferenceDayService _eventConferenceDayService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs
index bccfaf0e..7a450fc0 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs
@@ -8,8 +8,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class EventConferenceRoomsController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class EventConferenceRoomsController : BaseController
     {
         private readonly IEventConferenceRoomService _eventConferenceRoomService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs
index 980bf5b3..f4b52d59 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs
@@ -8,8 +8,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class EventConferenceTracksController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class EventConferenceTracksController : BaseController
     {
         private readonly IEventConferenceTrackService _eventConferenceTrackService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs
index 8015a272..f1d683a8 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs
@@ -8,8 +8,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class EventFeedbackController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class EventFeedbackController : BaseController
     {
         private readonly IApiPrincipal _apiPrincipal;
         private readonly IEventFeedbackService _eventFeedbackService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs
index abe70c0c..ea07538b 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs
@@ -8,8 +8,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class EventsController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class EventsController : BaseController
     {
         private readonly IEventService _eventService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs b/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs
index e178ee9e..26ea54ac 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs
@@ -10,8 +10,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class FursuitsController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class FursuitsController : BaseController
     {
         private readonly IFursuitBadgeService _fursuitBadgeService;
         private readonly ICollectingGameService _collectingGameService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs b/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs
index 2387ef87..0898c077 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs
@@ -10,8 +10,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class ImagesController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class ImagesController : BaseController
     {
         private readonly IImageService _imageService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs
index ac928561..647ec87f 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs
@@ -9,8 +9,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class KnowledgeEntriesController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class KnowledgeEntriesController : BaseController
     {
         private readonly IKnowledgeEntryService _knowledgeEntryService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs
index b1e68cd1..211c94f1 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs
@@ -9,8 +9,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class KnowledgeGroupsController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class KnowledgeGroupsController : BaseController
     {
         private readonly IKnowledgeGroupService _knowledgeGroupService;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs b/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs
index dfc002c0..4bba2b74 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs
@@ -14,8 +14,8 @@ namespace Eurofurence.App.Server.Web.Controllers
     /// <summary>
     /// FindMe1
     /// </summary>
-    [Route("Api/v2/[controller]")]
-    public class MapsController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class MapsController : BaseController
     {
         private readonly ILinkFragmentValidator _linkFragmentValidator;
         private readonly IMapService _mapService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs b/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs
index 06594298..70fd1623 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs
@@ -7,8 +7,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class PushNotificationsController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class PushNotificationsController : BaseController
     {
         private readonly IPushEventMediator _pushEventMediator;
         private readonly IApiPrincipal _apiPrincipal;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/RichPreviewController.cs b/src/Eurofurence.App.Server.Web/Controllers/RichPreviewController.cs
index b6a4dca1..018c2268 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/RichPreviewController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/RichPreviewController.cs
@@ -8,7 +8,7 @@
 namespace Eurofurence.App.Server.Web.Controllers
 {
     [Route("Link")]
-    public class RichPreviewController : Controller
+    public class RichPreviewController : BaseController
     {
         private readonly IEventService _eventService;
         private readonly IEventConferenceDayService _eventConferenceDayService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
index d2fa9032..3818d11d 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
@@ -13,8 +13,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class SyncController
+    [Route("Api/[cid]/[controller]")]
+    public class SyncController : BaseController
     {
         private readonly IAnnouncementService _announcementService;
         private readonly IDealerService _dealerService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs b/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
index 578446c5..a5a522ce 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
@@ -8,8 +8,8 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/v2/[controller]")]
-    public class TokensController : Controller
+    [Route("Api/[cid]/[controller]")]
+    public class TokensController : BaseController
     {
         private readonly IApiPrincipal _apiPrincipal;
         private readonly IAuthenticationHandler _authenticationHandler;
diff --git a/src/Eurofurence.App.Server.Web/Extensions/CidRouteValueProvider.cs b/src/Eurofurence.App.Server.Web/Extensions/CidRouteValueProvider.cs
new file mode 100644
index 00000000..8d746b7e
--- /dev/null
+++ b/src/Eurofurence.App.Server.Web/Extensions/CidRouteValueProvider.cs
@@ -0,0 +1,13 @@
+using Microsoft.AspNetCore.Mvc.Routing;
+using System;
+
+namespace Eurofurence.App.Server.Web.Extensions
+{
+    public class CidRouteBaseAttribute : Attribute, IRouteValueProvider
+    {
+        internal static string Value { get; set; } = string.Empty;
+
+        public string RouteKey => "cid";
+        public string RouteValue => Value;
+    }
+}

From 206af4e6f390f58b778fd0a03394717e0042d248 Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Mon, 5 Nov 2018 10:45:57 +0100
Subject: [PATCH 2/8] Adding ConventionIdentifier (replacing ConventionNumber)

---
 .../appsettings.sample.json                       |  1 +
 .../Abstractions/ConventionSettings.cs            |  2 +-
 .../ArtShow/ItemActivityService.cs                |  2 +-
 .../Fursuits/FursuitBadgeService.cs               |  2 +-
 .../Security/AuthenticationHandler.cs             |  4 ++--
 .../Telegram/AdminConversation.cs                 |  6 +++---
 .../Telegram/BotManager.cs                        |  2 +-
 src/Eurofurence.App.Server.Web/Startup.cs         | 15 ++++++---------
 src/Eurofurence.App.Tools.CliToolBox/Program.cs   |  2 +-
 9 files changed, 17 insertions(+), 19 deletions(-)

diff --git a/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json b/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json
index 30c8c8bb..e25d79ae 100644
--- a/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json
+++ b/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json
@@ -1,6 +1,7 @@
 {
   "global": {
     "conventionNumber": 23,
+    "conventionIdentifier": "EF25",
     "regSysAuthenticationEnabled":  0
   },
   "logLevel": 1,
diff --git a/src/Eurofurence.App.Server.Services/Abstractions/ConventionSettings.cs b/src/Eurofurence.App.Server.Services/Abstractions/ConventionSettings.cs
index 1394754b..f23afa63 100644
--- a/src/Eurofurence.App.Server.Services/Abstractions/ConventionSettings.cs
+++ b/src/Eurofurence.App.Server.Services/Abstractions/ConventionSettings.cs
@@ -2,7 +2,7 @@ namespace Eurofurence.App.Server.Services.Abstractions
 {
     public class ConventionSettings
     {
-        public int ConventionNumber { get; set; }
+        public string ConventionIdentifier { get; set; }
         public bool IsRegSysAuthenticationEnabled { get; set; }
         public string ApiBaseUrl { get; set; }
     }
diff --git a/src/Eurofurence.App.Server.Services/ArtShow/ItemActivityService.cs b/src/Eurofurence.App.Server.Services/ArtShow/ItemActivityService.cs
index a90a9c50..0d504556 100644
--- a/src/Eurofurence.App.Server.Services/ArtShow/ItemActivityService.cs
+++ b/src/Eurofurence.App.Server.Services/ArtShow/ItemActivityService.cs
@@ -50,7 +50,7 @@ public async Task ImportActivityLogAsync(TextReader logReader)
                 var newRecord = new ItemActivityRecord()
                 {
                     Id = Guid.NewGuid(),
-                    OwnerUid = $"RegSys:{_conventionSettings.ConventionNumber}:{csvRecord.RegNo}",
+                    OwnerUid = $"RegSys:{_conventionSettings.ConventionIdentifier}:{csvRecord.RegNo}",
                     ASIDNO = csvRecord.ASIDNO,
                     ArtistName = csvRecord.ArtistName,
                     ArtPieceTitle = csvRecord.ArtPieceTitle,
diff --git a/src/Eurofurence.App.Server.Services/Fursuits/FursuitBadgeService.cs b/src/Eurofurence.App.Server.Services/Fursuits/FursuitBadgeService.cs
index 93de58cc..bfde7ba2 100644
--- a/src/Eurofurence.App.Server.Services/Fursuits/FursuitBadgeService.cs
+++ b/src/Eurofurence.App.Server.Services/Fursuits/FursuitBadgeService.cs
@@ -53,7 +53,7 @@ public async Task<Guid> UpsertFursuitBadgeAsync(FursuitBadgeRegistration registr
                 }
 
                 record.ExternalReference = registration.BadgeNo.ToString();
-                record.OwnerUid = $"RegSys:{_conventionSettings.ConventionNumber}:{registration.RegNo}";
+                record.OwnerUid = $"RegSys:{_conventionSettings.ConventionIdentifier}:{registration.RegNo}";
                 record.Gender = registration.Gender;
                 record.Name = registration.Name;
                 record.Species = registration.Species;
diff --git a/src/Eurofurence.App.Server.Services/Security/AuthenticationHandler.cs b/src/Eurofurence.App.Server.Services/Security/AuthenticationHandler.cs
index d1517861..283c9a64 100644
--- a/src/Eurofurence.App.Server.Services/Security/AuthenticationHandler.cs
+++ b/src/Eurofurence.App.Server.Services/Security/AuthenticationHandler.cs
@@ -74,7 +74,7 @@ public async Task<AuthenticationResponse> AuthorizeViaRegSys(RegSysAuthenticatio
                 return null;
             }
 
-            var uid = $"RegSys:{_conventionSettings.ConventionNumber}:{authenticationResult.RegNo}";
+            var uid = $"RegSys:{_conventionSettings.ConventionIdentifier}:{authenticationResult.RegNo}";
 
             var identityRecord = await _regSysIdentityRepository.FindOneAsync(a => a.Uid == uid);
             if (identityRecord == null)
@@ -114,7 +114,7 @@ public async Task<AuthenticationResponse> AuthorizeViaRegSys(RegSysAuthenticatio
                 new Claim(ClaimTypes.Name, uid),
                 new Claim(ClaimTypes.GivenName, authenticationResult.Username),
                 new Claim(ClaimTypes.PrimarySid, authenticationResult.RegNo.ToString()),
-                new Claim(ClaimTypes.GroupSid, _conventionSettings.ConventionNumber.ToString()),
+                new Claim(ClaimTypes.GroupSid, _conventionSettings.ConventionIdentifier.ToString()),
                 new Claim(ClaimTypes.System, "RegSys")
             };
 
diff --git a/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs b/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs
index 5ea81c21..492b69ef 100644
--- a/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs
+++ b/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs
@@ -289,7 +289,7 @@ public async Task CommandSendMessage()
                                         return;
                                     }
 
-                                    var recipientUid = $"RegSys:{_conventionSettings.ConventionNumber}:{regNo}";
+                                    var recipientUid = $"RegSys:{_conventionSettings.ConventionIdentifier}:{regNo}";
                                     var messageId = await _privateMessageService.SendPrivateMessageAsync(new SendPrivateMessageRequest()
                                     {
                                         AuthorName = $"{from}",
@@ -341,7 +341,7 @@ public async Task CommandCollectionGameUnban()
                     }
 
                     var result = await _collectingGameService.UnbanPlayerAsync(
-                            $"RegSys:{_conventionSettings.ConventionNumber}:{regNo}");
+                            $"RegSys:{_conventionSettings.ConventionIdentifier}:{regNo}");
 
                     if (result.IsSuccessful)
                     {
@@ -660,7 +660,7 @@ private async Task CommandCollectionGameRegisterFursuit()
                                 return;
                             }
 
-                            if (badge.OwnerUid != $"RegSys:{_conventionSettings.ConventionNumber}:{regNo}")
+                            if (badge.OwnerUid != $"RegSys:{_conventionSettings.ConventionIdentifier}:{regNo}")
                             {
                                 await ReplyAsync($"*Error*: Fursuit badge with no *{fursuitBadgeNo}* exists, but does *not* belong to reg no *{regNo}*. Aborting.");
                                 return;
diff --git a/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs b/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs
index f5309f6f..72e71b36 100644
--- a/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs
+++ b/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs
@@ -171,7 +171,7 @@ private async Task<InlineQueryResult[]> QueryEvents(string query)
                         messageBuilder.Append($"\n\n_{desc}_");
                     }
 
-                    messageBuilder.Append($"\n\n[Read more...](https://www.eurofurence.org/EF{_conventionSettings.ConventionNumber}/schedule/events/{e.SourceEventId}.en.html)");
+                    messageBuilder.Append($"\n\n[Read more...](https://www.eurofurence.org/{_conventionSettings.ConventionIdentifier}/schedule/events/{e.SourceEventId}.en.html)");
 
                     return new InlineQueryResultArticle()
                     {
diff --git a/src/Eurofurence.App.Server.Web/Startup.cs b/src/Eurofurence.App.Server.Web/Startup.cs
index 120b53d6..2ed254bb 100644
--- a/src/Eurofurence.App.Server.Web/Startup.cs
+++ b/src/Eurofurence.App.Server.Web/Startup.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 using System.IO;
 using System.Text;
 using Amazon;
@@ -64,6 +65,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
             var database = client.GetDatabase(Configuration["mongoDb:database"]);
 
             BsonClassMapping.Register();
+            CidRouteBaseAttribute.Value = Configuration["global:conventionIdentifier"];
 
             services.AddCors(options =>
             {
@@ -167,7 +169,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
             });
             builder.RegisterInstance(new ConventionSettings()
             {
-                ConventionNumber = Convert.ToInt32(Configuration["global:conventionNumber"]),
+                ConventionIdentifier = Configuration["global:conventionIdentifier"],
                 IsRegSysAuthenticationEnabled = Convert.ToInt32(Configuration["global:regSysAuthenticationEnabled"]) == 1,
                 ApiBaseUrl = Configuration["global:apiBaseUrl"]
             });
@@ -212,7 +214,8 @@ public void Configure(
             IApplicationBuilder app,
             IHostingEnvironment env,
             ILoggerFactory loggerFactory,
-            IApplicationLifetime appLifetime)
+            IApplicationLifetime appLifetime
+        )
         {
             var loggerConfiguration = new LoggerConfiguration().Enrich.FromLogContext();
 
@@ -292,13 +295,7 @@ public void Configure(
                 }
             });
 
-            app.UseMvc(routes =>
-            {
-                routes.MapRoute(
-                    "default",
-                    "{controller=Test}/{action=Index}/{id?}");
-            });
-
+            app.UseMvc();
             app.UseSwagger();
 
             app.UseSwaggerUI(c =>
diff --git a/src/Eurofurence.App.Tools.CliToolBox/Program.cs b/src/Eurofurence.App.Tools.CliToolBox/Program.cs
index 012cd15c..b096ce24 100644
--- a/src/Eurofurence.App.Tools.CliToolBox/Program.cs
+++ b/src/Eurofurence.App.Tools.CliToolBox/Program.cs
@@ -48,7 +48,7 @@ private static int Main(string[] args)
 
             builder.RegisterInstance(new ConventionSettings
             {
-                ConventionNumber = Convert.ToInt32(Configuration["global:conventionNumber"]),
+                ConventionIdentifier = Configuration["global:conventionIdentifier"],
                 IsRegSysAuthenticationEnabled = Convert.ToInt32(Configuration["global:regSysAuthenticationEnabled"]) == 1
             });
 

From 4324bde895587054326fe5a43a7caa5be2a9d6a8 Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Mon, 5 Nov 2018 10:47:21 +0100
Subject: [PATCH 3/8] Removing Unneccessary Usings

---
 .../Controllers/ArtShowController.cs                        | 6 +-----
 .../Controllers/CommunicationController.cs                  | 1 -
 .../Controllers/SyncController.cs                           | 1 -
 .../Controllers/TokensController.cs                         | 4 +---
 .../Extensions/ResultExtensions.cs                          | 3 +--
 src/Eurofurence.App.Server.Web/Startup.cs                   | 1 -
 6 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs b/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
index 58bd02c6..5c23f837 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
@@ -1,12 +1,8 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.IO;
-using System.Text;
 using System.Threading.Tasks;
 using Eurofurence.App.Server.Services.Abstractions.ArtShow;
-using Eurofurence.App.Server.Services.Abstractions.Fursuits;
 using Eurofurence.App.Server.Services.Abstractions.Security;
-using Eurofurence.App.Server.Web.Extensions;
 using Eurofurence.App.Server.Web.Swagger;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs b/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
index 03152a80..c48f61df 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using System.Threading.Tasks;
 using Eurofurence.App.Domain.Model.Communication;
 using Eurofurence.App.Server.Services.Abstractions.Communication;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
index 3818d11d..30d7b9c5 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
@@ -7,7 +7,6 @@
 using Eurofurence.App.Server.Services.Abstractions.Images;
 using Eurofurence.App.Server.Services.Abstractions.Knowledge;
 using Eurofurence.App.Server.Services.Abstractions.Maps;
-using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Logging;
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs b/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
index a5a522ce..ca81c014 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
@@ -1,6 +1,4 @@
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Eurofurence.App.Common.Validation;
+using System.Threading.Tasks;
 using Eurofurence.App.Server.Services.Abstractions.Security;
 using Eurofurence.App.Server.Web.Extensions;
 using Microsoft.AspNetCore.Authorization;
diff --git a/src/Eurofurence.App.Server.Web/Extensions/ResultExtensions.cs b/src/Eurofurence.App.Server.Web/Extensions/ResultExtensions.cs
index 98826ee3..439ed683 100644
--- a/src/Eurofurence.App.Server.Web/Extensions/ResultExtensions.cs
+++ b/src/Eurofurence.App.Server.Web/Extensions/ResultExtensions.cs
@@ -1,5 +1,4 @@
-using Eurofurence.App.Common;
-using Eurofurence.App.Common.Results;
+using Eurofurence.App.Common.Results;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 
diff --git a/src/Eurofurence.App.Server.Web/Startup.cs b/src/Eurofurence.App.Server.Web/Startup.cs
index 2ed254bb..0ea7ac5f 100644
--- a/src/Eurofurence.App.Server.Web/Startup.cs
+++ b/src/Eurofurence.App.Server.Web/Startup.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Diagnostics;
 using System.IO;
 using System.Text;
 using Amazon;

From 7c975976ca516ca981381a42a96e788b8324ba81 Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Mon, 5 Nov 2018 10:49:41 +0100
Subject: [PATCH 4/8] Adding ConventionIdentifier to /Sync

---
 .../Storage/AggregatedDeltaResponse.cs                     | 2 ++
 .../Controllers/SyncController.cs                          | 7 ++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/Eurofurence.App.Domain.Model/Storage/AggregatedDeltaResponse.cs b/src/Eurofurence.App.Domain.Model/Storage/AggregatedDeltaResponse.cs
index a14c6c7b..b2a04511 100644
--- a/src/Eurofurence.App.Domain.Model/Storage/AggregatedDeltaResponse.cs
+++ b/src/Eurofurence.App.Domain.Model/Storage/AggregatedDeltaResponse.cs
@@ -10,6 +10,8 @@ namespace Eurofurence.App.Domain.Model.Sync
 {
     public class AggregatedDeltaResponse
     {
+        public string ConventionIdentifier { get; set; }
+
         public DateTime? Since { get; set; }
         public DateTime CurrentDateTimeUtc { get; set; }
 
diff --git a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
index 30d7b9c5..aac9b93f 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Threading.Tasks;
 using Eurofurence.App.Domain.Model.Sync;
+using Eurofurence.App.Server.Services.Abstractions;
 using Eurofurence.App.Server.Services.Abstractions.Announcements;
 using Eurofurence.App.Server.Services.Abstractions.Dealers;
 using Eurofurence.App.Server.Services.Abstractions.Events;
@@ -26,6 +27,7 @@ public class SyncController : BaseController
         private readonly IKnowledgeGroupService _knowledgeGroupService;
         private readonly ILogger _logger;
         private readonly IMapService _mapService;
+        private readonly ConventionSettings _conventionSettings;
 
         public SyncController(
             ILoggerFactory loggerFactory,
@@ -38,7 +40,8 @@ public SyncController(
             IImageService imageService,
             IDealerService dealerService,
             IAnnouncementService announcementService,
-            IMapService mapService
+            IMapService mapService,
+            ConventionSettings conventionSettings
         )
         {
             _logger = loggerFactory.CreateLogger(GetType());
@@ -52,6 +55,7 @@ IMapService mapService
             _dealerService = dealerService;
             _announcementService = announcementService;
             _mapService = mapService;
+            _conventionSettings = conventionSettings;
         }
 
         /// <summary>
@@ -66,6 +70,7 @@ public async Task<AggregatedDeltaResponse> GetDeltaAsync([FromQuery] DateTime? s
 
             var response = new AggregatedDeltaResponse
             {
+                ConventionIdentifier = _conventionSettings.ConventionIdentifier,
                 Since = since,
                 CurrentDateTimeUtc = DateTime.UtcNow,
 

From 5005127a0fb34c0abbafa40b82ab7a8dfe8fd6a5 Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Mon, 5 Nov 2018 12:47:33 +0100
Subject: [PATCH 5/8] Making Log Stream use Convention Identifier

---
 src/Eurofurence.App.Server.Web/Startup.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Eurofurence.App.Server.Web/Startup.cs b/src/Eurofurence.App.Server.Web/Startup.cs
index 0ea7ac5f..6166166a 100644
--- a/src/Eurofurence.App.Server.Web/Startup.cs
+++ b/src/Eurofurence.App.Server.Web/Startup.cs
@@ -228,7 +228,7 @@ IApplicationLifetime appLifetime
             {
                 loggerConfiguration.MinimumLevel.Is(LogEventLevel.Verbose);
 
-                var logGroupName = Configuration["aws:cloudwatch:logGroupName"] + "/" + env.EnvironmentName;
+                var logGroupName = Configuration["aws:cloudwatch:logGroupName"] + "/" + Configuration["global:conventionIdentifier"];
 
                 AWSCredentials credentials =
                     new BasicAWSCredentials(Configuration["aws:accessKey"], Configuration["aws:secret"]);

From 8a2de79c6aa6016504a4065d9350fec248afb3f5 Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Mon, 5 Nov 2018 12:53:12 +0100
Subject: [PATCH 6/8] Firebase broadcast topics now derived from
 ConventionIdentifier

---
 .../appsettings.sample.json                       |  7 +------
 .../PushNotifications/FirebaseConfiguration.cs    |  3 ---
 .../PushNotifications/FirebaseChannelManager.cs   | 15 ++++++++++-----
 src/Eurofurence.App.Server.Web/Startup.cs         |  3 ---
 4 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json b/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json
index e25d79ae..3c5517de 100644
--- a/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json
+++ b/src/Eurofurence.App.Server.KestrelHost/appsettings.sample.json
@@ -21,12 +21,7 @@
     "targetTopic": "Debug"
   },
   "firebase": {
-    "authorizationKey": "",
-    "targetTopic": {
-      "all": "",
-      "android": "",
-      "ios": ""
-    }
+    "authorizationKey": ""
   },
   "aws": {
     "accessKey": "",
diff --git a/src/Eurofurence.App.Server.Services/Abstractions/PushNotifications/FirebaseConfiguration.cs b/src/Eurofurence.App.Server.Services/Abstractions/PushNotifications/FirebaseConfiguration.cs
index 7006aba9..2984decf 100644
--- a/src/Eurofurence.App.Server.Services/Abstractions/PushNotifications/FirebaseConfiguration.cs
+++ b/src/Eurofurence.App.Server.Services/Abstractions/PushNotifications/FirebaseConfiguration.cs
@@ -3,8 +3,5 @@ namespace Eurofurence.App.Server.Services.Abstractions.PushNotifications
     public class FirebaseConfiguration
     {
         public string AuthorizationKey { get; set; }
-        public string TargetTopicAll { get; set; }
-        public string TargetTopicAndroid { get; set; }
-        public string TargetTopicIos { get; set; }
     }
 }
\ No newline at end of file
diff --git a/src/Eurofurence.App.Server.Services/PushNotifications/FirebaseChannelManager.cs b/src/Eurofurence.App.Server.Services/PushNotifications/FirebaseChannelManager.cs
index 368d4044..550cfcc4 100644
--- a/src/Eurofurence.App.Server.Services/PushNotifications/FirebaseChannelManager.cs
+++ b/src/Eurofurence.App.Server.Services/PushNotifications/FirebaseChannelManager.cs
@@ -9,6 +9,7 @@
 using Eurofurence.App.Domain.Model.Abstractions;
 using Eurofurence.App.Domain.Model.Announcements;
 using Eurofurence.App.Domain.Model.PushNotifications;
+using Eurofurence.App.Server.Services.Abstractions;
 using Eurofurence.App.Server.Services.Abstractions.PushNotifications;
 using Newtonsoft.Json;
 
@@ -18,14 +19,18 @@ public class FirebaseChannelManager : IFirebaseChannelManager
     {
         private readonly FirebaseConfiguration _configuration;
         private readonly IEntityRepository<PushNotificationChannelRecord> _pushNotificationRepository;
+        private readonly ConventionSettings _conventionSettings;
 
         public FirebaseChannelManager(
             FirebaseConfiguration configuration,
-            IEntityRepository<PushNotificationChannelRecord> pushNotificationRepository)
+            IEntityRepository<PushNotificationChannelRecord> pushNotificationRepository,
+            ConventionSettings conventionSettings
+            )
 
         {
             _configuration = configuration;
             _pushNotificationRepository = pushNotificationRepository;
+            _conventionSettings = conventionSettings;
         }
 
         private Task<IEnumerable<PushNotificationChannelRecord>> GetRecipientChannelAsync(string recipientUid)
@@ -46,7 +51,7 @@ public Task PushAnnouncementNotificationAsync(AnnouncementRecord announcement)
                         Text = announcement.Content.RemoveMarkdown(),
                         RelatedId = announcement.Id
                     },
-                    to = $"/topics/{_configuration.TargetTopicAndroid}"
+                    to = $"/topics/{_conventionSettings.ConventionIdentifier}-android"
                 }), 
                 SendPushNotificationAsync(new
                 {
@@ -62,7 +67,7 @@ public Task PushAnnouncementNotificationAsync(AnnouncementRecord announcement)
                     },
                     content_available = true,
                     priority = "high",
-                    to = $"/topics/{_configuration.TargetTopicIos}"
+                    to = $"/topics/{_conventionSettings.ConventionIdentifier}-ios"
                 })
             );
         }
@@ -116,7 +121,7 @@ public Task PushSyncRequestAsync()
                     {
                         Event = "Sync",
                     },
-                    to = $"/topics/{_configuration.TargetTopicAndroid}"
+                    to = $"/topics/{_conventionSettings.ConventionIdentifier}-android"
                 }),
                 SendPushNotificationAsync(new
                 {
@@ -126,7 +131,7 @@ public Task PushSyncRequestAsync()
                     },
                     content_available = true,
                     priority = "high",
-                    to = $"/topics/{_configuration.TargetTopicIos}"
+                    to = $"/topics/{_conventionSettings.ConventionIdentifier}-ios"
                 })
             );
         }
diff --git a/src/Eurofurence.App.Server.Web/Startup.cs b/src/Eurofurence.App.Server.Web/Startup.cs
index 6166166a..98b619dc 100644
--- a/src/Eurofurence.App.Server.Web/Startup.cs
+++ b/src/Eurofurence.App.Server.Web/Startup.cs
@@ -181,9 +181,6 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
             builder.RegisterInstance(new FirebaseConfiguration
             {
                 AuthorizationKey = Configuration["firebase:authorizationKey"],
-                TargetTopicAll = Configuration["firebase:targetTopic:all"],
-                TargetTopicAndroid = Configuration["firebase:targetTopic:android"],
-                TargetTopicIos = Configuration["firebase:targetTopic:ios"]
             });
             builder.RegisterInstance(new TelegramConfiguration
             {

From 30f28b7e7ff1cad6ed8e72f3b95df25fa6e3d8d9 Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Mon, 5 Nov 2018 14:39:15 +0100
Subject: [PATCH 7/8] Updated Swagger; remove con identifier from routes

---
 .../Controllers/AnnouncementsController.cs    |  2 +-
 .../Controllers/ArtShowController.cs          |  2 +-
 .../Controllers/CommunicationController.cs    |  2 +-
 .../Controllers/DealersController.cs          |  2 +-
 .../EventConferenceDaysController.cs          |  2 +-
 .../EventConferenceRoomsController.cs         |  2 +-
 .../EventConferenceTracksController.cs        |  2 +-
 .../Controllers/EventFeedbackController.cs    |  2 +-
 .../Controllers/EventsController.cs           |  2 +-
 .../Controllers/FursuitsController.cs         |  2 +-
 .../Controllers/ImagesController.cs           |  2 +-
 .../Controllers/KnowledgeEntriesController.cs |  2 +-
 .../Controllers/KnowledgeGroupsController.cs  |  2 +-
 .../Controllers/MapsController.cs             |  2 +-
 .../PushNotificationsController.cs            |  2 +-
 .../Controllers/SyncController.cs             |  2 +-
 .../Controllers/TokensController.cs           |  2 +-
 .../Eurofurence.App.Server.Web.csproj         |  2 +-
 src/Eurofurence.App.Server.Web/Startup.cs     | 29 ++++++++++---------
 19 files changed, 34 insertions(+), 31 deletions(-)

diff --git a/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs b/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs
index d84ccdc2..92920821 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/AnnouncementsController.cs
@@ -10,7 +10,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class AnnouncementsController : BaseController
     {
         private readonly IAnnouncementService _announcementService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs b/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
index 5c23f837..fa0e68bc 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/ArtShowController.cs
@@ -9,7 +9,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class ArtShowController : BaseController
     {
         private readonly IItemActivityService _itemActivityService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs b/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
index c48f61df..a29d51c7 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/CommunicationController.cs
@@ -10,7 +10,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class CommunicationController : BaseController
     {
         private readonly IApiPrincipal _apiPrincipal;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs b/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs
index dc26cf8f..addf53fe 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/DealersController.cs
@@ -8,7 +8,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class DealersController : BaseController
     {
         private readonly IDealerService _dealerService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs
index 3a1acfa9..204cc1ef 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceDaysController.cs
@@ -8,7 +8,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class EventConferenceDaysController : BaseController
     {
         private readonly IEventConferenceDayService _eventConferenceDayService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs
index 7a450fc0..7220ee4b 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceRoomsController.cs
@@ -8,7 +8,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class EventConferenceRoomsController : BaseController
     {
         private readonly IEventConferenceRoomService _eventConferenceRoomService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs
index f4b52d59..769ada85 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventConferenceTracksController.cs
@@ -8,7 +8,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class EventConferenceTracksController : BaseController
     {
         private readonly IEventConferenceTrackService _eventConferenceTrackService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs
index f1d683a8..5ad3a247 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventFeedbackController.cs
@@ -8,7 +8,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class EventFeedbackController : BaseController
     {
         private readonly IApiPrincipal _apiPrincipal;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs b/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs
index ea07538b..ec8bb469 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/EventsController.cs
@@ -8,7 +8,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class EventsController : BaseController
     {
         private readonly IEventService _eventService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs b/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs
index 26ea54ac..600d8133 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/FursuitsController.cs
@@ -10,7 +10,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class FursuitsController : BaseController
     {
         private readonly IFursuitBadgeService _fursuitBadgeService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs b/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs
index 0898c077..1d4a4b97 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/ImagesController.cs
@@ -10,7 +10,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class ImagesController : BaseController
     {
         private readonly IImageService _imageService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs
index 647ec87f..8e401931 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeEntriesController.cs
@@ -9,7 +9,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class KnowledgeEntriesController : BaseController
     {
         private readonly IKnowledgeEntryService _knowledgeEntryService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs
index 211c94f1..510e314b 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/KnowledgeGroupsController.cs
@@ -9,7 +9,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class KnowledgeGroupsController : BaseController
     {
         private readonly IKnowledgeGroupService _knowledgeGroupService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs b/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs
index 4bba2b74..023691b6 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/MapsController.cs
@@ -14,7 +14,7 @@ namespace Eurofurence.App.Server.Web.Controllers
     /// <summary>
     /// FindMe1
     /// </summary>
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class MapsController : BaseController
     {
         private readonly ILinkFragmentValidator _linkFragmentValidator;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs b/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs
index 70fd1623..4f4ec66e 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/PushNotificationsController.cs
@@ -7,7 +7,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class PushNotificationsController : BaseController
     {
         private readonly IPushEventMediator _pushEventMediator;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
index aac9b93f..8f311c85 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/SyncController.cs
@@ -13,7 +13,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class SyncController : BaseController
     {
         private readonly IAnnouncementService _announcementService;
diff --git a/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs b/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
index ca81c014..9e5bd1b6 100644
--- a/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
+++ b/src/Eurofurence.App.Server.Web/Controllers/TokensController.cs
@@ -6,7 +6,7 @@
 
 namespace Eurofurence.App.Server.Web.Controllers
 {
-    [Route("Api/[cid]/[controller]")]
+    [Route("Api/[controller]")]
     public class TokensController : BaseController
     {
         private readonly IApiPrincipal _apiPrincipal;
diff --git a/src/Eurofurence.App.Server.Web/Eurofurence.App.Server.Web.csproj b/src/Eurofurence.App.Server.Web/Eurofurence.App.Server.Web.csproj
index 5b0c39b1..71282d68 100644
--- a/src/Eurofurence.App.Server.Web/Eurofurence.App.Server.Web.csproj
+++ b/src/Eurofurence.App.Server.Web/Eurofurence.App.Server.Web.csproj
@@ -39,7 +39,7 @@
     <PackageReference Include="Serilog.Sinks.AwsCloudWatch" Version="3.0.97" />
     <PackageReference Include="Serilog.Sinks.ColoredConsole" Version="3.0.1" />
     <PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
-    <PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/Eurofurence.App.Server.Web/Startup.cs b/src/Eurofurence.App.Server.Web/Startup.cs
index 98b619dc..aeb738ed 100644
--- a/src/Eurofurence.App.Server.Web/Startup.cs
+++ b/src/Eurofurence.App.Server.Web/Startup.cs
@@ -43,6 +43,7 @@ namespace Eurofurence.App.Server.Web
     public class Startup
     {
         private readonly IHostingEnvironment _hostingEnvironment;
+        private ConventionSettings _conventionSettings;
         private ILogger _logger;
 
         public Startup(IHostingEnvironment hostingEnvironment)
@@ -63,8 +64,15 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
             var client = new MongoClient(new MongoUrl(Configuration["mongoDb:url"]));
             var database = client.GetDatabase(Configuration["mongoDb:database"]);
 
+            _conventionSettings = new ConventionSettings()
+            {
+                ConventionIdentifier = Configuration["global:conventionIdentifier"],
+                IsRegSysAuthenticationEnabled = Convert.ToInt32(Configuration["global:regSysAuthenticationEnabled"]) == 1,
+                ApiBaseUrl = Configuration["global:apiBaseUrl"]
+            };
+
             BsonClassMapping.Register();
-            CidRouteBaseAttribute.Value = Configuration["global:conventionIdentifier"];
+            CidRouteBaseAttribute.Value = _conventionSettings.ConventionIdentifier;
 
             services.AddCors(options =>
             {
@@ -95,13 +103,13 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
             
             services.AddSwaggerGen(options =>
             {
-                options.SwaggerDoc("v2", new Info
+                options.SwaggerDoc("api", new Info
                 {
-                    Version = "v2",
+                    Version = "current",
                     Title = "Eurofurence API for Mobile Apps",
                     Description = "",
                     TermsOfService = "None",
-                    Contact = new Contact {Name = "Luchs", Url = "https://telegram.me/pinselohrkater"}
+                    Contact = new Contact {Name = "Luchs", Url = "https://telegram.me/pinselohrkater"},
                 });
 
                 options.AddSecurityDefinition("Bearer", new ApiKeyScheme
@@ -166,12 +174,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
             {
                 DefaultTokenLifeTime = TimeSpan.FromDays(30)
             });
-            builder.RegisterInstance(new ConventionSettings()
-            {
-                ConventionIdentifier = Configuration["global:conventionIdentifier"],
-                IsRegSysAuthenticationEnabled = Convert.ToInt32(Configuration["global:regSysAuthenticationEnabled"]) == 1,
-                ApiBaseUrl = Configuration["global:apiBaseUrl"]
-            });
+            builder.RegisterInstance(_conventionSettings);
             builder.RegisterInstance(new WnsConfiguration
             {
                 ClientId = Configuration["wns:clientId"],
@@ -292,13 +295,13 @@ IApplicationLifetime appLifetime
             });
 
             app.UseMvc();
-            app.UseSwagger();
 
+            app.UseSwagger();
             app.UseSwaggerUI(c =>
             {
-                c.RoutePrefix = "swagger/v2/ui";
+                c.RoutePrefix = $"swagger/ui";
                 c.DocExpansion(DocExpansion.None);
-                c.SwaggerEndpoint("/swagger/v2/swagger.json", "API v2");
+                c.SwaggerEndpoint($"/swagger/api/swagger.json", "Current API");
                 c.EnableDeepLinking();
             });
 

From c30e7e85c247102875534dffdfa6f5222f2592ca Mon Sep 17 00:00:00 2001
From: Luchs <luchs@pinselohr.ch>
Date: Wed, 7 Nov 2018 10:58:48 +0100
Subject: [PATCH 8/8] Moving message notifications to async queue

---
 .../Communication/IPrivateMessageService.cs   |  2 +
 .../Communication/PrivateMessageService.cs    | 47 ++++++++++++++++++-
 .../DependencyResolution/AutofacModule.cs     |  5 +-
 .../FlushPrivateMessageNotificationsJob.cs    | 29 ++++++++++++
 .../Jobs/JobRegistry.cs                       |  3 ++
 .../Jobs/UpdateNewsJob.cs                     |  6 +++
 src/Eurofurence.App.Server.Web/Startup.cs     |  1 +
 7 files changed, 90 insertions(+), 3 deletions(-)
 create mode 100644 src/Eurofurence.App.Server.Web/Jobs/FlushPrivateMessageNotificationsJob.cs

diff --git a/src/Eurofurence.App.Server.Services/Abstractions/Communication/IPrivateMessageService.cs b/src/Eurofurence.App.Server.Services/Abstractions/Communication/IPrivateMessageService.cs
index b28f18db..4d5255be 100644
--- a/src/Eurofurence.App.Server.Services/Abstractions/Communication/IPrivateMessageService.cs
+++ b/src/Eurofurence.App.Server.Services/Abstractions/Communication/IPrivateMessageService.cs
@@ -13,6 +13,8 @@ public interface IPrivateMessageService
 
         Task<Guid> SendPrivateMessageAsync(SendPrivateMessageRequest request, string senderUid = "System");
 
+        Task<int> FlushPrivateMessageQueueNotifications(int messageCount = 10);
+
         Task<PrivateMessageStatus> GetPrivateMessageStatusAsync(Guid messageId);
 
         Task<IEnumerable<PrivateMessageRecord>> GetPrivateMessagesForSenderAsync(string senderUid);
diff --git a/src/Eurofurence.App.Server.Services/Communication/PrivateMessageService.cs b/src/Eurofurence.App.Server.Services/Communication/PrivateMessageService.cs
index db4995b2..57c6f81b 100644
--- a/src/Eurofurence.App.Server.Services/Communication/PrivateMessageService.cs
+++ b/src/Eurofurence.App.Server.Services/Communication/PrivateMessageService.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading.Tasks;
@@ -14,6 +15,7 @@ public class PrivateMessageService : EntityServiceBase<PrivateMessageRecord>,
         IPrivateMessageService
     {
         private readonly IPushEventMediator _pushEventMediator;
+        private readonly ConcurrentQueue<QueuedNotificationParameters> _notificationQueue = new ConcurrentQueue<QueuedNotificationParameters>();
 
         public PrivateMessageService(
             IEntityRepository<PrivateMessageRecord> entityRepository,
@@ -53,6 +55,15 @@ public async Task<IEnumerable<PrivateMessageRecord>> GetPrivateMessagesForRecipi
             return message.ReadDateTimeUtc;
         }
 
+
+        private struct QueuedNotificationParameters
+        {
+            public string RecipientUid;
+            public string ToastTitle;
+            public string ToastMessage;
+            public Guid RelatedId;
+        }
+
         public async Task<Guid> SendPrivateMessageAsync(SendPrivateMessageRequest request, string senderUid = "System")
         {
             var entity = new PrivateMessageRecord
@@ -67,8 +78,14 @@ public async Task<Guid> SendPrivateMessageAsync(SendPrivateMessageRequest reques
             entity.NewId();
 
             await InsertOneAsync(entity);
-            await _pushEventMediator.PushPrivateMessageNotificationAsync(
-                request.RecipientUid, request.ToastTitle, request.ToastMessage, entity.Id);
+
+            _notificationQueue.Enqueue(new QueuedNotificationParameters()
+            {
+                RecipientUid = request.RecipientUid,
+                ToastTitle = request.ToastTitle,
+                ToastMessage = request.ToastMessage,
+                RelatedId = entity.Id
+            });
 
             return entity.Id;
         }
@@ -98,5 +115,31 @@ public async Task<IEnumerable<PrivateMessageRecord>> GetPrivateMessagesForSender
         {
             return await FindAllAsync(a => a.SenderUid == senderUid);
         }
+
+        public async Task<int> FlushPrivateMessageQueueNotifications(int messageCount = 10)
+        {
+            var flushedMessageCount = 0;
+
+            for(int i = 0; i < messageCount; i++)
+            {
+                if (_notificationQueue.TryDequeue(out QueuedNotificationParameters parameters))
+                {
+                    await _pushEventMediator.PushPrivateMessageNotificationAsync(
+                        parameters.RecipientUid,
+                        parameters.ToastTitle,
+                        parameters.ToastMessage,
+                        parameters.RelatedId
+                    );
+
+                    flushedMessageCount++;
+                }
+                else
+                { 
+                    break;
+                }
+            }
+
+            return flushedMessageCount;
+        }
     }
 }
\ No newline at end of file
diff --git a/src/Eurofurence.App.Server.Services/DependencyResolution/AutofacModule.cs b/src/Eurofurence.App.Server.Services/DependencyResolution/AutofacModule.cs
index f0dabe49..d0061ff5 100644
--- a/src/Eurofurence.App.Server.Services/DependencyResolution/AutofacModule.cs
+++ b/src/Eurofurence.App.Server.Services/DependencyResolution/AutofacModule.cs
@@ -55,7 +55,10 @@ protected override void Load(ContainerBuilder builder)
             builder.RegisterType<PushNotificationChannelStatisticsService>().As<IPushNotificationChannelStatisticsService>();
             builder.RegisterType<FirebaseChannelManager>().As<IFirebaseChannelManager>();
             builder.RegisterType<LinkFragmentValidator>().As<ILinkFragmentValidator>();
-            builder.RegisterType<PrivateMessageService>().As<IPrivateMessageService>();
+            builder.RegisterType<PrivateMessageService>()
+                .As<IPrivateMessageService>()
+                .SingleInstance();
+
             builder.RegisterType<RegSysAlternativePinAuthenticationProvider>()
                 .As<IRegSysAlternativePinAuthenticationProvider>();
 
diff --git a/src/Eurofurence.App.Server.Web/Jobs/FlushPrivateMessageNotificationsJob.cs b/src/Eurofurence.App.Server.Web/Jobs/FlushPrivateMessageNotificationsJob.cs
new file mode 100644
index 00000000..14ce90ba
--- /dev/null
+++ b/src/Eurofurence.App.Server.Web/Jobs/FlushPrivateMessageNotificationsJob.cs
@@ -0,0 +1,29 @@
+using Eurofurence.App.Server.Services.Abstractions.Communication;
+using FluentScheduler;
+using Microsoft.Extensions.Logging;
+
+namespace Eurofurence.App.Server.Web.Jobs
+{
+    public class FlushPrivateMessageNotificationsJob : IJob
+    {
+        private readonly ILogger _logger;
+        private readonly IPrivateMessageService _privateMessageService;
+
+        public FlushPrivateMessageNotificationsJob(
+            ILoggerFactory loggerFactory,
+            IPrivateMessageService privateMessageService
+        )
+        {
+            _logger = loggerFactory.CreateLogger(GetType());
+            _privateMessageService = privateMessageService;
+        }
+
+        public void Execute()
+        {
+            var count = _privateMessageService.FlushPrivateMessageQueueNotifications().Result;
+            if (count == 0) return;
+
+            _logger.LogInformation($"Flushed {count} messages");
+        }
+    }
+}
diff --git a/src/Eurofurence.App.Server.Web/Jobs/JobRegistry.cs b/src/Eurofurence.App.Server.Web/Jobs/JobRegistry.cs
index 78379859..e561f5ae 100644
--- a/src/Eurofurence.App.Server.Web/Jobs/JobRegistry.cs
+++ b/src/Eurofurence.App.Server.Web/Jobs/JobRegistry.cs
@@ -8,6 +8,9 @@ public class JobRegistry : Registry
     {
         public JobRegistry(IConfiguration configuration)
         {
+            NonReentrantAsDefault();
+
+            Schedule<FlushPrivateMessageNotificationsJob>().ToRunEvery(1).Seconds();
             Schedule<UpdateNewsJob>().ToRunNow().AndEvery(Convert.ToInt32(configuration["updateNews:secondsInterval"])).Seconds();
         }
     }
diff --git a/src/Eurofurence.App.Server.Web/Jobs/UpdateNewsJob.cs b/src/Eurofurence.App.Server.Web/Jobs/UpdateNewsJob.cs
index 466a4cb4..6efd4a75 100644
--- a/src/Eurofurence.App.Server.Web/Jobs/UpdateNewsJob.cs
+++ b/src/Eurofurence.App.Server.Web/Jobs/UpdateNewsJob.cs
@@ -59,6 +59,12 @@ public async Task ExecuteAsync()
             using (var client = new HttpClient())
             {
                 var url = _configuration["source:url"];
+                if (String.IsNullOrWhiteSpace(url))
+                {
+                    _logger.LogDebug("Empty soruce url; cancelling job", url);
+                    return;
+                }
+
                 _logger.LogDebug("Fetching data from {url}", url);
                 response = await client.GetStringAsync(url);
             }
diff --git a/src/Eurofurence.App.Server.Web/Startup.cs b/src/Eurofurence.App.Server.Web/Startup.cs
index aeb738ed..6a7f63ad 100644
--- a/src/Eurofurence.App.Server.Web/Startup.cs
+++ b/src/Eurofurence.App.Server.Web/Startup.cs
@@ -204,6 +204,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
                 .Keyed<IConfiguration>("updateNews").As<IConfiguration>();
             
             builder.RegisterType<UpdateNewsJob>().WithAttributeFiltering().AsSelf();
+            builder.RegisterType<FlushPrivateMessageNotificationsJob>().AsSelf();
 
             var container = builder.Build();
             return container.Resolve<IServiceProvider>();