Skip to content

Commit

Permalink
Users/rbrands/2024 12 12 (#150)
Browse files Browse the repository at this point in the history
* Version of link tools updated

* Version number

* No dependencies on LinkPreview library

* Version updated

* Mermaid diagram

* Update README.md

* Update README.md

* Update README.md

* Update README.md

---------

Co-authored-by: Robert Brands (RiwaAdmin) <[email protected]>
  • Loading branch information
rbrands and Robert Brands (RiwaAdmin) authored Dec 13, 2024
1 parent 79cd31b commit 97857df
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 69 deletions.
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 = "2024-11-22";
public const string VERSION = "2024-12-14";
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
73 changes: 14 additions & 59 deletions MeetUpFunctions/GetLinkPreview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Web.Http;
using MSiccDev.Libs.LinkTools.LinkPreview;
using MeetUpPlanner.Shared;

namespace MeetUpPlanner.Functions
Expand All @@ -19,13 +18,11 @@ public class GetLinkPreview
{
private readonly ILogger _logger;
private ServerSettingsRepository _serverSettingsRepository;
private LinkPreviewService _linkPreviewRepository;

public GetLinkPreview(ILogger<GetLinkPreview> logger, ServerSettingsRepository serverSettingsRepository, LinkPreviewService linkPreviewRepository)
public GetLinkPreview(ILogger<GetLinkPreview> logger, ServerSettingsRepository serverSettingsRepository)
{
_logger = logger;
_serverSettingsRepository = serverSettingsRepository;
_linkPreviewRepository = linkPreviewRepository;
}


Expand All @@ -39,78 +36,36 @@ public async Task<IActionResult> Run(
{
tenant = null;
}
ServerSettings serverSettings = await _serverSettingsRepository.GetServerSettings(tenant);
string keyWord = req.Headers[Constants.HEADER_KEYWORD];
if (String.IsNullOrEmpty(keyWord) || !serverSettings.IsUser(keyWord))
{
return new BadRequestErrorMessageResult("Keyword is missing or wrong.");
}

string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
LinkPreview linkPreview = JsonConvert.DeserializeObject<LinkPreview>(requestBody);

LinkPreviewRequest previewRequest = new LinkPreviewRequest(linkPreview.Url);
try
{
LinkPreviewRequest previewResponse = await _linkPreviewRepository.GetLinkDataAsync(previewRequest, false, true, false, true);
linkPreview.Title = System.Web.HttpUtility.HtmlDecode(previewResponse.Result.Title);
linkPreview.Description = System.Web.HttpUtility.HtmlDecode(previewResponse.Result.Description);
linkPreview.ImageUrl = ParseKomootLink(linkPreview.Url.ToString());
if (null == linkPreview.ImageUrl)
{
linkPreview.ImageUrl = previewResponse.Result.ImageUrl;
}
linkPreview.Url = previewResponse.Result.Url;
linkPreview.CanoncialUrl = previewResponse.Result.CanoncialUrl;
linkPreview.Success = previewResponse.IsSuccess;
if (!linkPreview.Success && null != previewResponse.Error)
var web = new HtmlAgilityPack.HtmlWeb();
var doc = await web.LoadFromWebAsync(linkPreview.Url.ToString());

linkPreview.Title = doc.DocumentNode.SelectSingleNode("//head/title")?.InnerText;
linkPreview.Description = doc.DocumentNode.SelectSingleNode("//meta[@name='description']")?.GetAttributeValue("content", string.Empty);

if (linkPreview.ImageUrl == null)
{
linkPreview.Message = previewResponse.Error.Message;
var imageNode = doc.DocumentNode.SelectSingleNode("//meta[@property='og:image']") ??
doc.DocumentNode.SelectSingleNode("//meta[@name='twitter:image']");
linkPreview.ImageUrl = new Uri(imageNode?.GetAttributeValue("content", string.Empty));
}

linkPreview.Success = true;
}
catch (Exception ex)
{
linkPreview.Success = false;
linkPreview.Message = ex.Message;
_logger.LogError(ex, $"GetLinkPreview() failed. Message {ex.Message}");
}

return new OkObjectResult(linkPreview);
}
private Uri ParseKomootLink(string url)
{
Uri uri = new Uri(url);
HttpUtility httpUtility = new HttpUtility();

if (!url.Contains("komoot", StringComparison.InvariantCultureIgnoreCase))
{
// No Komoot ==> don't analyze this url
return null;
}
string tour = null;
Uri komootImageLink = null;

string[] segments = uri.Segments;
for (int i = 0; i < segments.Length; i++)
{
if (segments[i].CompareTo("tour/") == 0)
{
tour = segments[i + 1];
break;
}
}
if (null != tour)
{
string shareTokenQuery = uri.Query;
NameValueCollection queryArgs = HttpUtility.ParseQueryString(shareTokenQuery);
string shareToken = queryArgs["share_token"];
if (null == shareToken)
{
// Only links without share_token
komootImageLink = new Uri($"https://www.komoot.de/tour/{tour}/embed?image=1&hm=true&width=800&height=700");
}
}
return komootImageLink;
}

}

Expand Down
4 changes: 1 addition & 3 deletions MeetUpFunctions/MeetUpPlanner.Functions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.23.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.71" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.46.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="5.3.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.6.0" />
<PackageReference Include="MSiccDev.Libs.LinkTools.Core" Version="1.0.21261.1" />
<PackageReference Include="MSiccDev.Libs.LinkTools.Data" Version="1.0.21261.1" />
<PackageReference Include="MSiccDev.Libs.LinkTools.LinkPreview" Version="1.0.21262.1" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.1" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string",
"defaultValue": "RB-PD-RGP-004Functions",
"metadata": {
"_parameterType": "resourceGroup",
"description": "Der Name der Ressourcengruppe für die Ressource. Es wird empfohlen, Ressourcen für eine bessere Nachverfolgung in derselben Ressourcengruppe zu platzieren."
}
},
"resourceGroupLocation": {
"type": "string",
"defaultValue": "westeurope",
"metadata": {
"_parameterType": "location",
"description": "Der Standort der Ressourcengruppe. Ressourcengruppen können andere Standorte als Ressourcen aufweisen."
}
},
"resourceLocation": {
"type": "string",
"defaultValue": "[parameters('resourceGroupLocation')]",
"metadata": {
"_parameterType": "location",
"description": "Der Standort der Ressource. Verwenden Sie standardmäßig den Standort der Ressourcengruppe, sofern der Ressourcenanbieter dort unterstützt wird."
}
}
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"name": "[parameters('resourceGroupName')]",
"location": "[parameters('resourceGroupLocation')]",
"apiVersion": "2019-10-01"
},
{
"type": "Microsoft.Resources/deployments",
"name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('meetupplanner', subscription().subscriptionId)))]",
"resourceGroup": "[parameters('resourceGroupName')]",
"apiVersion": "2019-10-01",
"dependsOn": [
"[parameters('resourceGroupName')]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"name": "meetupplanner",
"type": "Microsoft.Storage/storageAccounts",
"location": "[parameters('resourceLocation')]",
"apiVersion": "2017-10-01"
}
]
}
}
}
],
"metadata": {
"_dependencyType": "storage.azure"
}
}
7 changes: 6 additions & 1 deletion MeetUpFunctions/Properties/serviceDependencies.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"dependencies": {}
"dependencies": {
"storage1": {
"type": "storage",
"connectionId": "AzureWebJobsStorage"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"dependencies": {
"storage1": {
"resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Storage/storageAccounts/meetupplanner",
"type": "storage.azure",
"connectionId": "AzureWebJobsStorage"
}
}
}
2 changes: 0 additions & 2 deletions MeetUpFunctions/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Cosmos;
using MSiccDev.Libs.LinkTools.LinkPreview;
using MeetUpPlanner.Shared;

[assembly: FunctionsStartup(typeof(MeetUpPlanner.Functions.Startup))]
Expand Down Expand Up @@ -52,7 +51,6 @@ public override void Configure(IFunctionsHostBuilder builder)
builder.Services.AddSingleton(new CosmosDBRepository<ExportLogItem>(config, cosmosClient));
builder.Services.AddSingleton(new ServerSettingsRepository(config, cosmosClient));
builder.Services.AddSingleton<ChallengeRepository>();
builder.Services.AddSingleton(new LinkPreviewService());
builder.Services.AddSingleton<CosmosDBRepository<ContentWithChaptersItem>>();
builder.Services.AddSingleton<BlobStorageRepository>();
builder.Services.AddHttpClient();
Expand Down
2 changes: 1 addition & 1 deletion MeetUpPlanner/Client/MeetUpPlanner.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Blazored.TextEditor" Version="1.1.0" />
<PackageReference Include="CurrieTechnologies.Razor.Clipboard" Version="1.6.0" />
<PackageReference Include="Radzen.Blazor" Version="5.6.5" />
<PackageReference Include="Radzen.Blazor" Version="5.6.15" />
<PackageReference Include="Microsoft.AspNetCore.Components" Version="8.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.11" />
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 @@ -52,7 +52,7 @@
</div>

@code {
private const string clientVersion = "2024-11-22";
private const string clientVersion = "2024-12-14";
private string serverVersion = "tbd";
private string functionsVersion = "tbd";

Expand Down
2 changes: 1 addition & 1 deletion MeetUpPlanner/Server/Controllers/UtilController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class UtilController : ControllerBase
{
private readonly MeetUpFunctions _meetUpFunctions;
private readonly ILogger<UtilController> logger;
const string serverVersion = "2024-11-22";
const string serverVersion = "2024-12-14";
string functionsVersion = "tbd";

public UtilController(ILogger<UtilController> logger, MeetUpFunctions meetUpFunctions)
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,45 @@ Therefore the following design principles for this web-app are:
* Availability of "private" MeetUps: The ability to organize a MeetUp and protect it with a "keyword" that can be given to potential participants.
* Adaptable: The application has a front-end layer implemented with <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor">ASP.NET Core Blazor</a> The application logic is provided via serverless <a href="https://docs.microsoft.com/en-us/azure/azure-functions/">Azure Functions</a>. In this way it is possible to use the application layer independently with a different front-end.

# Architecture
The application is divided into two parts:
* The front-end is a Blazor WebAssembly application. It is a Single Page Application (SPA) that runs in the browser. The application is hosted on an Azure App Service.
* The back-end is a set of Azure Functions that provide the business logic for the application. The Azure Functions are hosted in an Azure Functions App. The Azure Functions are implemented in C# and use the .NET Core 3.1 runtime. The Azure Functions use Azure Cosmos DB to store the data.

```mermaid
graph TD
subgraph Client
A[Blazor WebAssembly]
end
subgraph Server
B[ASP.NET Core Web API]
C[Several Controllers]
D[MeetUpFunctions]
end
subgraph Azure
G[Azure Functions]
H[Function1]
I[Function2]
E[Repositories]
end
subgraph Database
F[CosmosDB]
end
A -->|HTTP Requests| B
B -->|Controller Actions| C
C -->|Business Logic| D
H -->|Data Access| E
I -->|Data Access| E
E -->|Database Operations| F
D -->|Invoke Functions| G
G -->|Function Logic| H
G -->|Function Logic| I
```

# About this repository
* Folder "MeetUpFunctions" has the source code of the Azure Functions used for the backend. The master branch is CI enabled with GitHub Actions and deployed to the slot "dev" of the Azure Functions App.
* Folder MeetUpPlanner holds the source code of the Blazor WebAssembly and the ASP.NET Core hosting app. The master branch is CI enabled with GitHub Action and deployed slot "dev" of the web application.
Expand Down

0 comments on commit 97857df

Please sign in to comment.