Skip to content

Commit

Permalink
Federation (#126)
Browse files Browse the repository at this point in the history
* Libraries updated

* Setting federation fiel

* Interim version

* Working version

* Working version

* Working federation

* NuGet packages updated

* NuGet Package updated

---------

Co-authored-by: Robert Brands (RiwaAdmin) <[email protected]>
  • Loading branch information
rbrands and Robert Brands (RiwaAdmin) authored Sep 14, 2023
1 parent dd57520 commit 29ad671
Show file tree
Hide file tree
Showing 24 changed files with 286 additions and 23 deletions.
1 change: 1 addition & 0 deletions MeetUpFunctions/AddParticipantToCalendarItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public async Task<IActionResult> Run(
{
participant.Tenant = tenant;
}
participant.Federation = serverSettings.Federation;

participant = await _cosmosRepository.UpsertItem(participant);
BackendResult result = new BackendResult(true);
Expand Down
2 changes: 1 addition & 1 deletion MeetUpFunctions/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class Constants
public const string DEFAULT_DISCLAIMER = "Disclaimer";
public const string DEFAULT_GUEST_DISCLAIMER = "Guest Disclaimer";

public const string VERSION = "2023-05-09";
public const string VERSION = "2023-09-10";
public const int ADMINOVERBOOKFACTOR = 1; // no overbooking any more, because not needed

public const int LOG_TTL = 30 * 24 * 3600; // 30 days TTL for Log items
Expand Down
42 changes: 42 additions & 0 deletions MeetUpFunctions/CosmosDBRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace MeetUpPlanner.Functions
private CosmosClient _cosmosClient;
string _cosmosDbDatabase;
string _cosmosDbContainer;
const int MAX_PATCH_OPERATIONS = 10;


/// <summary>
/// Create repository, typically as singleton. Create CosmosClient before.
Expand Down Expand Up @@ -167,7 +169,47 @@ public async Task<T> UpsertItem(T item)

return response.Resource;
}
public async Task<T> PatchItem(string id, IReadOnlyList<PatchOperation> patchOperations, string timestamp = null)
{
Container container = _cosmosClient.GetDatabase(_cosmosDbDatabase).GetContainer(_cosmosDbContainer);
PartitionKey partitionKey = new PartitionKey(typeof(T).Name);

if (String.IsNullOrEmpty(id))
{
throw new ArgumentNullException("id");
}
PatchItemRequestOptions patchOption = new PatchItemRequestOptions();
if (null != timestamp)
{
patchOption.FilterPredicate = $"from c where c._ts = {timestamp}";
}
// PatchItem only supports up to 10 operations. If there are more than that given, create more batches and
// patch the document several times.
ItemResponse<T> response = null;
do
{
List<PatchOperation> po = new List<PatchOperation>(patchOperations.Take(MAX_PATCH_OPERATIONS));
response = await container.PatchItemAsync<T>(
id: id,
partitionKey: partitionKey,
patchOperations: po,
requestOptions: patchOption
);
patchOperations = new List<PatchOperation>(patchOperations.Skip(MAX_PATCH_OPERATIONS));
}
while (patchOperations.Count > 0);

return response.Resource;
}
public async Task<T> PatchField(string id, string fieldName, object value, string timestamp = null)
{
List<PatchOperation> patchOperations = new()
{
PatchOperation.Add($"/{fieldName}", value)
};

return await PatchItem(id, patchOperations, timestamp);
}

}
}
16 changes: 15 additions & 1 deletion MeetUpFunctions/GetExtendedCalendarItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,22 @@ public async Task<IActionResult> Run(
{
rawListOfCalendarItems = await _cosmosRepository.GetItems(d => d.StartDate > compareDate && d.Tenant.Equals(tenant));
}
IEnumerable<CalendarItem> rawCalendarItemsWithFederatedOnes = rawListOfCalendarItems;
if (!String.IsNullOrEmpty(serverSettings.Federation))
{
IEnumerable<CalendarItem> rawListOfFederatedCalendarItems;
if (null == tenant)
{
rawListOfFederatedCalendarItems = await _cosmosRepository.GetItems(d => d.StartDate > compareDate && (d.Tenant ?? String.Empty) == String.Empty && d.Federation == serverSettings.Federation);
}
else
{
rawListOfFederatedCalendarItems = await _cosmosRepository.GetItems(d => d.StartDate > compareDate && d.Tenant.Equals(tenant) && d.Federation == serverSettings.Federation);
}
rawCalendarItemsWithFederatedOnes = rawListOfCalendarItems.Concat(rawListOfFederatedCalendarItems);
}
List<ExtendedCalendarItem> resultCalendarItems = new List<ExtendedCalendarItem>(10);
foreach (CalendarItem item in rawListOfCalendarItems)
foreach (CalendarItem item in rawCalendarItemsWithFederatedOnes)
{
// Create ExtendedCalendarItem and get comments and participants
ExtendedCalendarItem extendedItem = new ExtendedCalendarItem(item);
Expand Down
6 changes: 3 additions & 3 deletions MeetUpFunctions/MeetUpPlanner.Functions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aliencube.AzureFunctions.Extensions.OpenApi.Core" Version="3.1.1" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.16.0" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.33.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.18.0" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.35.3" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="5.1.2" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="5.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.2.0" />
Expand Down
86 changes: 86 additions & 0 deletions MeetUpFunctions/RemoveFederation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using MeetUpPlanner.Shared;
using System.Web.Http;
using Aliencube.AzureFunctions.Extensions.OpenApi.Core.Attributes;


namespace MeetUpPlanner.Functions
{
public class RemoveFederation
{
private readonly ILogger _logger;
private ServerSettingsRepository _serverSettingsRepository;
private CosmosDBRepository<CalendarItem> _cosmosRepository;
private CosmosDBRepository<Participant> _participantRepository;
private NotificationSubscriptionRepository _subscriptionRepository;

public RemoveFederation(ILogger<WriteCalendarItem> logger,
ServerSettingsRepository serverSettingsRepository,
NotificationSubscriptionRepository subscriptionRepository,
CosmosDBRepository<Participant> participantRepository,
CosmosDBRepository<CalendarItem> cosmosRepository)
{
_logger = logger;
_serverSettingsRepository = serverSettingsRepository;
_cosmosRepository = cosmosRepository;
_participantRepository = participantRepository;
_subscriptionRepository = subscriptionRepository;
}

/// <summary>
/// Removes the federation from CalendarItem to the database. x-meetup-keyword must be set to admin keyword.
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[FunctionName("RemoveFederation")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function RemoveFederation processed a request.");
string tenant = req.Headers[Constants.HEADER_TENANT];
if (String.IsNullOrWhiteSpace(tenant))
{
tenant = null;
}
ServerSettings serverSettings;
if (null == tenant)
{
serverSettings = await _serverSettingsRepository.GetServerSettings();
}
else
{
serverSettings = await _serverSettingsRepository.GetServerSettings(tenant);
}

string keyWord = req.Headers[Constants.HEADER_KEYWORD];
if (String.IsNullOrEmpty(keyWord) || !serverSettings.IsAdmin(keyWord))
{
return new BadRequestErrorMessageResult("Keyword is missing or wrong.");
}
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
CalendarItem calendarItem = JsonConvert.DeserializeObject<CalendarItem>(requestBody);
if (null != tenant)
{
calendarItem.Tenant = tenant;
}
CalendarItem oldCalendarItem = null;
if (!String.IsNullOrEmpty(calendarItem.Id))
{
oldCalendarItem = await _cosmosRepository.GetItem(calendarItem.Id);
// Patching/removing federation makes only sense if the CalendarItem still lives in the database
await _cosmosRepository.PatchField(calendarItem.Id, "federation", String.Empty);
calendarItem = await _cosmosRepository.PatchField(calendarItem.Id, "federatedFrom", String.Empty);
}

return new OkObjectResult(calendarItem);
}
}
}
10 changes: 10 additions & 0 deletions MeetUpPlanner/Client/BackendApiRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,15 @@ public static string GetUrlFriendlyTitle(string title)
return urlFriendlyTitle;
}

public async Task RemoveFederation(CalendarItem calendarItem)
{
this.PrepareHttpClient();
HttpResponseMessage response = await _http.PostAsJsonAsync<CalendarItem>($"Calendar/removefederation", calendarItem);
response.EnsureSuccessStatusCode();
_http.DefaultRequestHeaders.Remove(HEADER_TENANT);
return;

}

}
}
16 changes: 8 additions & 8 deletions MeetUpPlanner/Client/MeetUpPlanner.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.16.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.18.0" />
<PackageReference Include="BlazorDownloadFile" Version="2.4.0.2" />
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0" />
<PackageReference Include="Blazored.TextEditor" Version="1.0.8" />
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
<PackageReference Include="Blazored.TextEditor" Version="1.1.0" />
<PackageReference Include="CurrieTechnologies.Razor.Clipboard" Version="1.6.0" />
<PackageReference Include="Radzen.Blazor" Version="4.10.4" />
<PackageReference Include="Microsoft.AspNetCore.Components" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.5" />
<PackageReference Include="Radzen.Blazor" Version="4.15.14" />
<PackageReference Include="Microsoft.AspNetCore.Components" Version="7.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.11" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.11" />
<PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion MeetUpPlanner/Client/Pages/About.razor
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
</div>

@code {
private const string clientVersion = "2023-05-09";
private const string clientVersion = "2023-09-10";
private string serverVersion = "tbd";
private string functionsVersion = "tbd";

Expand Down
21 changes: 19 additions & 2 deletions MeetUpPlanner/Client/Pages/Calendar.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
@inject AppState AppStateStore
@inject KeywordCheck KeywordCheck
@inject HttpClient Http
@inject BackendApiRepository Api
@inject NavigationManager NavigationManager
@inject NotificationService notificationService
@inject DialogService dialogService
Expand Down Expand Up @@ -70,6 +71,7 @@
}
<span class="badge badge-warning" hidden="@(!item.IsCross)">Cross</span>
<span class="badge badge-secondary" hidden="@(!item.IsTraining)">Training</span>
<span class="badge badge-success" hidden="@(!IsFederated(item))">@item.FederatedFrom</span>
@{
string badge = GetCalendarBadge(item);
if (!String.IsNullOrEmpty(badge))
Expand Down Expand Up @@ -180,7 +182,14 @@
<div class="card-footer">
<div class="btn-toolbar" role="toolbar" aria-label="Aktionen zur Ausfahrt">
<div class="btn-group mr-2" role="group" aria-label="Ändern">
@if (CheckIfUserIsHost(item) || KeywordCheck.IsAdmin)
@if (IsFederated(item))
{
if (KeywordCheck.IsAdmin)
{
<button class="btn btn-sm btn-outline-secondary" title="Einladung ablehnen" @onclick="@(() => RemoveFederation(item))"><span class="oi oi-x"></span></button>
}
}
else if (CheckIfUserIsHost(item) || KeywordCheck.IsAdmin)
{
<button class="btn btn-sm btn-outline-secondary" title="Ändern" @onclick="@(() => EditCalendarItem(item.Id))"><span class="oi oi-pencil"></span></button>
<button class="btn btn-sm btn-outline-secondary" title="Kopieren" @onclick="@(() => ConfirmClone(item))"><span class="oi oi-fork"></span></button>
Expand Down Expand Up @@ -409,7 +418,11 @@
}
//await ReadData();
}

protected async Task RemoveFederation(ExtendedCalendarItem calendarItem)
{
await Api.RemoveFederation(calendarItem);
await ReadData();
}
protected async Task Checkin(string itemId)
{
Participant participant = new Participant();
Expand Down Expand Up @@ -656,6 +669,10 @@
// notificationService.Notify(new NotificationMessage() { Severity = NotificationSeverity.Error, Summary = "Fehler", Detail = ex.Message, Duration = 4000 });
}
}
bool IsFederated(ExtendedCalendarItem calendarItem)
{
return calendarItem.IsFederated() && calendarItem.FederatedFrom != AppStateStore.Tenant.FederationKey;
}

}

Expand Down
33 changes: 32 additions & 1 deletion MeetUpPlanner/Client/Pages/NewMeetUp.razor
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,20 @@
</small>
</div>
}
@if (!String.IsNullOrEmpty(AppStateStore.ClientSettings.Federation))
{
<div class="form-group">
<div class="form-check">
<input type="checkbox" id="federation" checked="@IsFederated()" @oninput="@(() => CheckFederation())" aria-describedby="federationHelp" class="form-check-input">
<label for="federation" class="form-check-label">
Teilen mit @AppStateStore.ClientSettings.Federation?
</label>
</div>
<small id="federationHelp" class="form-text text-muted">
Auswählen, wenn die Ausfahrt/der Termin geteilt werden soll, d.h. auch beim Partner-Club angezeigt werden soll.
</small>
</div>
}
<div class="form-row">
<div class="form-group col-md-10">
<InputText id="link" aria-describedby="linkHelp" class="form-control" @bind-Value="meetup.Link" placeholder="Link zu weiterer Streckeninfo" title="Link zu weiterer Streckeninfo" />
Expand Down Expand Up @@ -703,7 +717,24 @@
_routeComment.CommentText = "Im MeetUpPlanner für eine Ausfahrt ausgewählt!";
_routeComment.AuthorDisplayName = AppStateStore.DisplayName;
}

protected void CheckFederation()
{
if (IsFederated())
{
meetup.Federation = String.Empty;
meetup.FederatedFrom = String.Empty;
}
else
{
meetup.Federation = AppStateStore.ClientSettings.Federation;
meetup.FederatedFrom = AppStateStore.Tenant.FederationKey;
}
}
protected bool IsFederated()
{
return (!String.IsNullOrEmpty(meetup.Federation));
}

private string StripEmptyHtml(string htmlContent)
{
htmlContent = (null == htmlContent || htmlContent.Equals("<p><br></p>")) ? null : htmlContent;
Expand Down
12 changes: 12 additions & 0 deletions MeetUpPlanner/Client/Shared/MeetUpCard.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@using MeetUpPlanner.Shared
@inject DialogService dialogService
@inject HttpClient Http
@inject BackendApiRepository Api
@inject AppState AppStateStore
@inject NavigationManager NavigationManager
@inject DialogService dialogService
Expand All @@ -24,6 +25,8 @@
<span class="badge badge-danger"><span class="oi oi-key" title="Private Ausfahrt"></span> @CalendarItem.PrivateKeyword</span>
}
<span class="badge badge-warning" hidden="@(!CalendarItem.IsCross)">Cross</span>
<span class="badge badge-secondary" hidden="@(!CalendarItem.IsTraining)">Training</span>
<span class="badge badge-success" hidden="@(!IsFederated())">@CalendarItem.FederatedFrom</span>
@{
string badge = GetCalendarBadge(CalendarItem);
if (!String.IsNullOrEmpty(badge))
Expand Down Expand Up @@ -222,6 +225,11 @@
bool isHost = !calendarItem.WithoutHost && (calendarItem.HostFirstName.Equals(FirstName) && calendarItem.HostLastName.Equals(LastName));
return isHost;
}
protected async Task RemoveFederation(ExtendedCalendarItem calendarItem)
{
await Api.RemoveFederation(calendarItem);
}


protected void EditCalendarItem(string itemId)
{
Expand Down Expand Up @@ -327,6 +335,10 @@
attachedInfoParameters.Add("Key", CalendarItem.AttachedInfoKey);
return attachedInfoParameters;
}
bool IsFederated()
{
return CalendarItem.IsFederated() && CalendarItem.FederatedFrom != AppStateStore.Tenant.FederationKey;
}


}
Loading

0 comments on commit 29ad671

Please sign in to comment.