Skip to content

Commit

Permalink
Merge pull request #239 from FBoucher/vnext
Browse files Browse the repository at this point in the history
New Release Version 2.0.2
  • Loading branch information
FBoucher authored Dec 29, 2020
2 parents 6844448 + 120f2e9 commit 634c80d
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 15 deletions.
28 changes: 28 additions & 0 deletions src/shortenerTools/Domain/StorageTableHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Table;

Expand Down Expand Up @@ -85,6 +87,32 @@ public async Task<List<ClickStatsEntity>> GetAllStatsByVanity(string vanity)
return lstShortUrl;
}

/// <summary>
/// Returns the ShortUrlEntity of the <paramref name="vanity"/>
/// </summary>
/// <param name="vanity"></param>
/// <returns>ShortUrlEntity</returns>
public async Task<ShortUrlEntity> GetShortUrlEntityByVanity(string vanity)
{
var tblUrls = GetUrlsTable();
TableContinuationToken token = null;
ShortUrlEntity shortUrlEntity = null;
do
{
TableQuery<ShortUrlEntity> query = new TableQuery<ShortUrlEntity>().Where(
filter: TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, vanity));
var queryResult = await tblUrls.ExecuteQuerySegmentedAsync(query, token);
shortUrlEntity = queryResult.Results.FirstOrDefault();
} while (token != null);

return shortUrlEntity;
}

public async Task<bool> IfShortUrlEntityExistByVanity(string vanity)
{
ShortUrlEntity shortUrlEntity = await GetShortUrlEntityByVanity(vanity);
return (shortUrlEntity != null);
}

public async Task<bool> IfShortUrlEntityExist(ShortUrlEntity row)
{
Expand Down
47 changes: 33 additions & 14 deletions src/shortenerTools/Domain/Utility.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -8,15 +9,21 @@ namespace Cloud5mins.domain
{
public static class Utility
{
private const string Alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
private static readonly int Base = Alphabet.Length;
//reshuffled for randomisation, same unique characters just jumbled up, you can replace with your own version
private const string ConversionCode = "FjTG0s5dgWkbLf_8etOZqMzNhmp7u6lUJoXIDiQB9-wRxCKyrPcv4En3Y21aASHV";
private static readonly int Base = ConversionCode.Length;
//sets the length of the unique code to add to vanity
private const int MinVanityCodeLength = 5;

public static async Task<string> GetValidEndUrl(string vanity, StorageTableHelper stgHelper)
{
if(string.IsNullOrEmpty(vanity))
if (string.IsNullOrEmpty(vanity))
{
var newKey = await stgHelper.GetNextTableId();
string getCode() => Encode(newKey);
string getCode() => Encode(newKey);
if (await stgHelper.IfShortUrlEntityExistByVanity(getCode()))
return await GetValidEndUrl(vanity, stgHelper);

return string.Join(string.Empty, getCode());
}
else
Expand All @@ -28,19 +35,31 @@ public static async Task<string> GetValidEndUrl(string vanity, StorageTableHelpe
public static string Encode(int i)
{
if (i == 0)
return Alphabet[0].ToString();
var s = string.Empty;
while (i > 0)
{
s += Alphabet[i % Base];
i = i / Base;
}
return ConversionCode[0].ToString();

return GenerateUniqueRandomToken(i);
}

return string.Join(string.Empty, s.Reverse());
public static string GetShortUrl(string host, string vanity)
{
return host + "/" + vanity;
}

public static string GetShortUrl(string host, string vanity){
return host + "/" + vanity;
// generates a unique, random, and alphanumeric token for the use as a url
//(not entirely secure but not sequential so generally not guessable)
public static string GenerateUniqueRandomToken(int uniqueId)
{
using (var generator = new RNGCryptoServiceProvider())
{
//minimum size I would suggest is 5, longer the better but we want short URLs!
var bytes = new byte[MinVanityCodeLength];
generator.GetBytes(bytes);
var chars = bytes
.Select(b => ConversionCode[b % ConversionCode.Length]);
var token = new string(chars.ToArray());
var reversedToken = string.Join(string.Empty, token.Reverse());
return uniqueId + reversedToken;
}
}

public static IActionResult CatchUnauthorize(ClaimsPrincipal principal, ILogger log)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>ZipDeploy</WebPublishMethod>
<PublishProvider>AzureWebSite</PublishProvider>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>http://patientcommsshortenertools2fxfh.azurewebsites.net</SiteUrlToLaunchAfterPublish>
<LaunchSiteAfterPublish>False</LaunchSiteAfterPublish>
<ResourceId>/subscriptions/1b64105e-78ea-4dde-b2b0-4031b5611c06/resourceGroups/PatientCommsGroupv2/providers/Microsoft.Web/sites/patientcommsshortenertools2fxfh</ResourceId>
<UserName>$patientcommsshortenertools2fxfh</UserName>
<_SavePWD>True</_SavePWD>
<PublishUrl>https://patientcommsshortenertools2fxfh.scm.azurewebsites.net/</PublishUrl>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_dependencyType": "function.windows.consumption"
},
"parameters": {
"resourceGroupName": {
"type": "string",
"defaultValue": "PatientCommsGroupv2",
"metadata": {
"description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
}
},
"resourceGroupLocation": {
"type": "string",
"defaultValue": "uksouth",
"metadata": {
"description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
}
},
"resourceName": {
"type": "string",
"defaultValue": "patientcommsshortenertools2fxfh",
"metadata": {
"description": "Name of the main resource to be created by this template."
}
},
"resourceLocation": {
"type": "string",
"defaultValue": "[parameters('resourceGroupLocation')]",
"metadata": {
"description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
}
}
},
"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(parameters('resourceName'), subscription().subscriptionId)))]",
"resourceGroup": "[parameters('resourceGroupName')]",
"apiVersion": "2019-10-01",
"dependsOn": [
"[parameters('resourceGroupName')]"
],
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"parameters": {
"resourceGroupName": {
"value": "[parameters('resourceGroupName')]"
},
"resourceGroupLocation": {
"value": "[parameters('resourceGroupLocation')]"
},
"resourceName": {
"value": "[parameters('resourceName')]"
},
"resourceLocation": {
"value": "[parameters('resourceLocation')]"
}
},
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string"
},
"resourceGroupLocation": {
"type": "string"
},
"resourceName": {
"type": "string"
},
"resourceLocation": {
"type": "string"
}
},
"variables": {
"storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]",
"storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]",
"function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]"
},
"resources": [
{
"location": "[parameters('resourceGroupLocation')]",
"name": "[variables('storage_name')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2017-10-01",
"tags": {
"[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty"
},
"properties": {
"supportsHttpsTrafficOnly": true
},
"sku": {
"name": "Standard_LRS"
},
"kind": "Storage"
},
{
"location": "[parameters('resourceLocation')]",
"name": "[parameters('resourceName')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"dependsOn": [
"[variables('storage_ResourceId')]"
],
"kind": "functionapp",
"properties": {
"name": "[parameters('resourceName')]",
"kind": "functionapp",
"httpsOnly": true,
"reserved": false
},
"identity": {
"type": "SystemAssigned"
},
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[variables('function_ResourceId')]"
],
"properties": {
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"WEBSITE_CONTENTSHARE": "[toLower(parameters('resourceName'))]",
"AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]",
"FUNCTIONS_EXTENSION_VERSION": "~3",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
]
}
]
}
}
}
]
}
2 changes: 1 addition & 1 deletion src/shortenerTools/UrlRedirect/UrlRedirect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static async Task<HttpResponseMessage> Run(
{
var config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddJsonFile("settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();

Expand Down

0 comments on commit 634c80d

Please sign in to comment.