public static async Task <IActionResult> RedirectDelete( [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "_api/v1/redirect/{key}")] HttpRequest req, [Table(TableNames.Redirects)] CloudTable redirectTable, string key, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { if (!claimsPrincipal.Identity.IsAuthenticated) { return(new UnauthorizedResult()); } RedirectEntity entity = await RedirectEntity.get(redirectTable, claimsPrincipal.Identity.Name, key); if (entity == null) { return(new NotFoundResult()); } if (entity.Recycled) { bool deleteSuccess = await RedirectEntity.delete(redirectTable, entity); return(deleteSuccess ? (IActionResult) new OkObjectResult(entity) : new BadRequestResult()); } entity.Recycled = true; bool success = await RedirectEntity.put(redirectTable, entity); return(success ? (IActionResult) new OkObjectResult(entity) : new BadRequestResult()); }
public static async Task <IActionResult> RedirectsGet( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "_api/v1/redirects")] HttpRequest req, [Table(TableNames.RedirectSessions)] CloudTable redirectTable, [Table(TableNames.Users)] CloudTable userTable, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { if (!claimsPrincipal.Identity.IsAuthenticated) { return(new UnauthorizedResult()); } UserEntity currentUser = await UserEntity.get(userTable, claimsPrincipal.Identity.Name); if (!currentUser.HasPermission(Permissions.SessionAdministrator)) { return(new UnauthorizedResult()); } RedirectEntity[] entities = await RedirectEntity.getAll(redirectTable); if (entities == null) { return(new NotFoundResult()); } return(new OkObjectResult(entities)); }
public static async Task <IActionResult> RedirectDelete( [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "_api/v1/redirect/{key}")] HttpRequest req, [Table(TableNames.RedirectSessions)] CloudTable redirectTable, [Table(TableNames.Users)] CloudTable userTable, string key, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { if (!claimsPrincipal.Identity.IsAuthenticated) { return(new UnauthorizedResult()); } UserEntity currentUser = await UserEntity.get(userTable, claimsPrincipal.Identity.Name); if (!currentUser.HasPermission(Permissions.SessionAdministrator)) { return(new UnauthorizedResult()); } RedirectEntity entity = await RedirectEntity.get(redirectTable, key); if (entity == null) { return(new NotFoundResult()); } bool deleteSuccess = await RedirectEntity.delete(redirectTable, entity); return(deleteSuccess ? (IActionResult) new OkObjectResult(entity) : new BadRequestResult()); }
public static async Task <IActionResult> RedirectAndHostGet( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "_api/v1/host/redirect/{host}/{key}")] HttpRequest req, [Table(TableNames.Redirects)] CloudTable redirectTable, [Table(TableNames.Domains)] CloudTable domainTable, string host, string key, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { List <DomainEntity> domainEntity = await DomainEntity.get(domainTable, host); if (domainEntity == null) { return(new NotFoundResult()); } RedirectEntity entity = await RedirectEntity.get(redirectTable, domainEntity.First().Account, key); if (entity == null) { return(new NotFoundResult()); } if (entity.Recycled) { return(new NotFoundResult()); } return(new OkObjectResult(new RedirectEntity(entity.PartitionKey, entity.RowKey, entity.RedirectTo, 0, new Dictionary <string, int>(), DateTime.Now, false))); }
public static async Task <IActionResult> RedirectsDashboardGet( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "_api/v1/redirects/dashboard")] HttpRequest req, [Table(TableNames.Redirects)] CloudTable redirectTable, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { if (!claimsPrincipal.Identity.IsAuthenticated) { return(new UnauthorizedResult()); } List <RedirectEntity> entities = (await RedirectEntity.get(redirectTable, claimsPrincipal.Identity.Name)); if (entities == null) { return(new NotFoundResult()); } RedirectEntity[] filteredEntities = entities.Where(redirect => redirect.Recycled == true).ToArray(); if (filteredEntities == null || filteredEntities.Length == 0) { return(new OkObjectResult(new RedirectEntity[] {})); } return(new OkObjectResult(filteredEntities)); }
public static async void ProcessClicks( [QueueTrigger(QueueNames.ProcessClicks)] string queuedHttpRequestString, [Table(TableNames.Redirects)] CloudTable redirectTable, [Table(TableNames.Domains)] CloudTable domainTable, [Queue(QueueNames.ProcessClicksGeo), StorageAccount("AzureWebJobsStorage")] ICollector <HttpRequestEntity> processClicksGeoQueue, ILogger log, ExecutionContext context) { HttpRequestEntity queuedHttpRequest = JsonConvert.DeserializeObject <HttpRequestEntity>(queuedHttpRequestString); var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); string nodeMaster = config["NODE_SYNC_MASTER_CONN"]; if (nodeMaster != null) { CloudStorageAccount storageAccount = CloudStorageAccount.Parse(nodeMaster); CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue destinationProcessClicksQueue = queueClient.GetQueueReference(QueueNames.ProcessClicks); await destinationProcessClicksQueue.AddMessageAsync(new CloudQueueMessage(JsonConvert.SerializeObject(queuedHttpRequest))); return; } List <DomainEntity> domains = await DomainEntity.get(domainTable, queuedHttpRequest.Host); if (domains == null) { throw new Exception($"Unable to process Geo lookup - domain {queuedHttpRequest.Host} wasn't found"); } string path = queuedHttpRequest.Path.Value.Substring(1); RedirectEntity redirect = await RedirectEntity.get(redirectTable, domains.First().Account, path); if (redirect != null) { redirect.ClickCount++; await RedirectEntity.put(redirectTable, redirect); processClicksGeoQueue.Add(queuedHttpRequest); log.LogInformation($"Successfully processed click for redirect query {queuedHttpRequest.Path} from {queuedHttpRequest.RemoteIpAddress}"); return; } log.LogError($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled hosts"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled hosts"); }
public ActionResult Create(RedirectEntity entity) { if (!ModelState.IsValid) { return(View(entity)); } _redirectService.Create(entity.Url, entity.Alias); return(RedirectToAction("Index")); }
public ActionResult Edit(string id) { var model = _redirectService.GetById(int.Parse(id)); var entity = new RedirectEntity(); entity.Id = id; entity.Alias = model.Alias; entity.Url = model.Url; return(View(entity)); }
public static async Task <dynamic[]?> All(CloudTable redirectTable) { RedirectEntity[] redirectData = await RedirectEntity.getAll(redirectTable); if (redirectData != null) { return(redirectData .Where(redirect => redirect.VideoLink != null && redirect.VideoLink != "") .Select((redirectData, index) => new { RowKey = redirectData.RowKey, VideoLink = redirectData.VideoLink }).ToArray()); } return(null); }
private static Document CreateDocumentForRedirect(RedirectEntity redirect) { var document = new Document(); document.Add(new Field("_type", "redirect", Field.Store.NO, Field.Index.NOT_ANALYZED)); document.Add(new Field("redirect_key", redirect.Id, Field.Store.YES, Field.Index.NOT_ANALYZED)); document.Add(new Field("redirect_tagPk", redirect.TagPartitionKey, Field.Store.YES, Field.Index.NOT_ANALYZED)); document.Add(new Field("redirect_tagRk", redirect.TagRowKey, Field.Store.YES, Field.Index.NOT_ANALYZED)); document.Add(new Field("redirect_media", redirect.Media ?? String.Empty, Field.Store.YES, Field.Index.NO)); document.Add(new Field("redirect_type", redirect.MediaType ?? String.Empty, Field.Store.YES, Field.Index.NO)); document.Add(new Field("redirect_uri", redirect.Uri, Field.Store.YES, Field.Index.NO)); return(document); }
private static IEnumerable <RedirectEntity> UpdateInstallationMediaLinksInSoftwareIdentityAndReturnWithRedirects(string tagPartitionKey, string tagRowKey, SoftwareIdentity swidtag) { foreach (var installationLink in swidtag.Links.Where(l => l.Relationship == FearTheCowboy.Iso19770.Schema.Relationship.InstallationMedia)) { var redirect = new RedirectEntity(tagPartitionKey, tagRowKey, installationLink.HRef.AbsoluteUri, installationLink.MediaType, installationLink.Media, null); swidtag.RemoveLink(installationLink.HRef); var redirectUri = new Uri(redirect.RedirectUri); swidtag.AddLink(redirectUri, FearTheCowboy.Iso19770.Schema.Relationship.InstallationMedia); yield return(redirect); } }
public ActionResult Edit(RedirectEntity entity) { if (!ModelState.IsValid) { return(View(entity)); } var model = _redirectService.GetById(int.Parse(entity.Id)); model.Alias = entity.Alias; model.Url = entity.Url; _redirectService.Update(model); return(RedirectToAction("Index")); }
public static async Task <IActionResult> RunRedirectVideo( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "redirect/video/{id}/")] HttpRequest req, [Table(TableNames.Cache)] CloudTable cacheTable, [Table(TableNames.RedirectSessions)] CloudTable sessionRedirectTable, [Queue(QueueNames.ProcessRedirectClicks), StorageAccount("AzureWebJobsStorage")] ICollector <HttpRequestEntity> processRedirectQueue, string id, ILogger log, ExecutionContext context) { id = id ?? req.Query["id"]; int numericId = 0; int.TryParse(id, out numericId); if (numericId > 0) { id = numericId.ToString(); } var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); RedirectEntity redirect = await RedirectEntity.get(sessionRedirectTable, id); if (redirect != null && redirect.VideoLink != null) { if (req.QueryString.ToString().IndexOf("check") < 0) { processRedirectQueue.Add(new HttpRequestEntity(req)); if (redirect.VideoLink.StartsWith("/") && redirect.VideoLink.Substring(1, 1) != "/") { return(new RedirectResult($"{config["REDIRECT_DESTINATION_HOST"]}{redirect.VideoLink}", false)); } return(new RedirectResult($"{redirect.VideoLink}", false)); } return(new AcceptedResult()); } return(new NotFoundResult()); }
public static async Task <IActionResult> RedirectPatch( [HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = "_api/v1/redirect/{key}")] HttpRequest req, [Table(TableNames.RedirectSessions)] CloudTable redirectTable, [Table(TableNames.Users)] CloudTable userTable, string key, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { if (!claimsPrincipal.Identity.IsAuthenticated) { return(new UnauthorizedResult()); } UserEntity currentUser = await UserEntity.get(userTable, claimsPrincipal.Identity.Name); if (!currentUser.HasPermission(Permissions.SessionAdministrator)) { return(new UnauthorizedResult()); } string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic entity = JsonConvert.DeserializeObject <dynamic>(requestBody); log.LogInformation($"Getting Redirect row for values {claimsPrincipal.Identity.Name} and {entity.RowKey}"); RedirectEntity existingEntity = await RedirectEntity.get(redirectTable, key); if (existingEntity == null) { return(new BadRequestObjectResult($"Redirect with {key} doesn't exist for {claimsPrincipal.Identity.Name}")); } existingEntity.RedirectTo = entity.redirectTo ??= existingEntity.RedirectTo; existingEntity.StartRedirectingMinutes = entity.startRedirectingMinutes ??= existingEntity.StartRedirectingMinutes; existingEntity.VideoLink = entity.videoLink ??= existingEntity.VideoLink; bool success = await RedirectEntity.put(redirectTable, existingEntity); if (!success) { return(new BadRequestObjectResult($"Error occurred updating {key} for {claimsPrincipal.Identity.Name}")); } return(new OkResult()); }
public static async Task <IActionResult> RedirectPost( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "_api/v1/redirect")] HttpRequest req, [Table(TableNames.RedirectSessions)] CloudTable redirectTable, [Table(TableNames.Users)] CloudTable userTable, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { if (!claimsPrincipal.Identity.IsAuthenticated) { return(new UnauthorizedResult()); } UserEntity currentUser = await UserEntity.get(userTable, claimsPrincipal.Identity.Name); if (!currentUser.HasPermission(Permissions.SessionAdministrator)) { return(new UnauthorizedResult()); } string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); RedirectEntity entity = JsonConvert.DeserializeObject <RedirectEntity>(requestBody); if (entity.RowKey == null || entity.RedirectTo == null) { return(new BadRequestObjectResult($"Please specify the key and redirectTo parameters in the request body")); } log.LogInformation($"Getting Redirect row for values {claimsPrincipal.Identity.Name} and {entity.RowKey}"); RedirectEntity existingEntity = await RedirectEntity.get(redirectTable, entity.RowKey); if (existingEntity != null) { return(new BadRequestObjectResult($"Redirect with {entity.RowKey} already exists for {claimsPrincipal.Identity.Name}")); } bool success = await RedirectEntity.put(redirectTable, entity.RowKey, entity.RedirectTo, entity.VideoLink, -10, 0, 0, 0, "{}", "{}", "{}"); if (!success) { return(new BadRequestObjectResult($"Error occurred creating {entity.RowKey} already exists for {claimsPrincipal.Identity.Name}")); } return(new OkResult()); }
public static async void ProcessRedirectsSync( [QueueTrigger(QueueNames.SynchroniseRedirects)] string node, [Table(TableNames.RedirectSessions)] CloudTable redirectTable, ILogger log, ExecutionContext context) { var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); string connectionString = config[$"NODE_SYNC_CONNECTION_{node}"]; if (connectionString == null) { throw new Exception($"No connection string found for node [{node}]. Aborting."); } CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString); CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); CloudTable destinationRedirectTable = tableClient.GetTableReference(TableNames.RedirectSessions); await destinationRedirectTable.CreateIfNotExistsAsync(); RedirectEntity[] redirects = await RedirectEntity.getAll(redirectTable); foreach (RedirectEntity redirect in redirects) { await RedirectEntity.put(destinationRedirectTable, redirect); } RedirectEntity[] destinationRedirects = await RedirectEntity.getAll(destinationRedirectTable); foreach (RedirectEntity destinationRedirect in destinationRedirects) { if (redirects.Where(checkRedirect => checkRedirect.RowKey == destinationRedirect.RowKey).Count() == 0) { await RedirectEntity.delete(destinationRedirectTable, destinationRedirect); } } }
public static async Task <IActionResult> RedirectGet( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "_api/v1/redirect/{key}")] HttpRequest req, [Table(TableNames.Redirects)] CloudTable redirectTable, string key, ILogger log, ExecutionContext context, ClaimsPrincipal claimsPrincipal) { if (!claimsPrincipal.Identity.IsAuthenticated) { return(new UnauthorizedResult()); } RedirectEntity entity = await RedirectEntity.get(redirectTable, claimsPrincipal.Identity.Name, key); if (entity == null) { return(new NotFoundResult()); } return(new OkObjectResult(entity)); }
public static async void ProcessRedirectsSync( [QueueTrigger(QueueNames.SynchroniseRedirects)] string node, [Table(TableNames.Redirects)] CloudTable redirectTable, [Table(TableNames.Domains)] CloudTable domainTable, [Queue(QueueNames.ProcessClicksGeo), StorageAccount("AzureWebJobsStorage")] ICollector <HttpRequestEntity> processClicksGeoQueue, ILogger log, ExecutionContext context) { var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); string connectionString = config[$"NODE_SYNC_CONNECTION_{node}"]; if (connectionString == null) { throw new Exception($"No connection string found for node [{node}]. Aborting."); } CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString); CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); CloudTable destinationRedirectTable = tableClient.GetTableReference(TableNames.Redirects); CloudTable destinationDomainTable = tableClient.GetTableReference(TableNames.Domains); await destinationRedirectTable.CreateIfNotExistsAsync(); await destinationDomainTable.CreateIfNotExistsAsync(); List <DomainEntity> domains = await DomainEntity.get(domainTable, null); List <string> uniqueAccounts = new List <string>(); foreach (DomainEntity domain in domains) { await DomainEntity.put(destinationDomainTable, domain); if (uniqueAccounts.FindIndex(checkAccount => checkAccount == domain.Account) == -1) { uniqueAccounts.Add(domain.Account); } } List <DomainEntity> destinationDomains = await DomainEntity.get(destinationDomainTable, null); foreach (DomainEntity destinationDomain in destinationDomains) { if (domains.FindIndex(checkDomain => checkDomain.RowKey == destinationDomain.RowKey) == -1) { await DomainEntity.delete(destinationRedirectTable, destinationDomain); } } foreach (string account in uniqueAccounts) { List <RedirectEntity> redirects = await RedirectEntity.get(redirectTable, account); foreach (RedirectEntity redirect in redirects) { await RedirectEntity.put(destinationRedirectTable, redirect); } List <RedirectEntity> destinationRedirects = await RedirectEntity.get(destinationRedirectTable, account); foreach (RedirectEntity destinationRedirect in destinationRedirects) { if (redirects.FindIndex(checkRedirect => checkRedirect.RowKey == destinationRedirect.RowKey) == -1) { await RedirectEntity.delete(destinationRedirectTable, destinationRedirect); } } } }
public static async Task <IActionResult> ShortNameGet( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "{shortName:regex([\\w\\d]+)}")] HttpRequest req, [Table(TableNames.Redirects)] CloudTable redirectTable, [Table(TableNames.Domains)] CloudTable domainTable, [Queue(QueueNames.ProcessClicks), StorageAccount("AzureWebJobsStorage")] ICollector <HttpRequestEntity> processClicksQueue, [Queue(QueueNames.NotFoundClicks), StorageAccount("AzureWebJobsStorage")] ICollector <HttpRequestEntity> notFoundClicksQueue, string shortName, ILogger log, ExecutionContext context) { List <DomainEntity> domains = await DomainEntity.get(domainTable, req.Host.Value); if (domains == null) { notFoundClicksQueue.Add(new NotFoundEntity(req, "Domain not handled")); return(new NotFoundResult()); } RedirectEntity redirect = await RedirectEntity.get(redirectTable, domains.First().Account, shortName); if (redirect == null) { var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); string nodeMaster = config["NODE_SYNC_MASTER_HOST"]; if (nodeMaster == null) { notFoundClicksQueue.Add(new NotFoundEntity(req, "Node master not found")); return(new NotFoundResult()); } string nodeMasterLookupUri = $"https://{nodeMaster}/_api/v1/host/redirect/{req.Host.Value}/{shortName}"; var client = new HttpClient(); var getResponse = await client.GetAsync(nodeMasterLookupUri); if (getResponse.StatusCode != HttpStatusCode.OK) { notFoundClicksQueue.Add(new NotFoundEntity(req, "Node master returned not found")); return(new NotFoundResult()); } string masterResponseString = await getResponse.Content.ReadAsStringAsync(); redirect = JsonConvert.DeserializeObject <RedirectEntity>(masterResponseString); await RedirectEntity.put(redirectTable, redirect); } if (redirect.Recycled) { notFoundClicksQueue.Add(new NotFoundEntity(req, "Short name has been recycled")); return(new NotFoundResult()); } req.HttpContext.Response.Headers.Add("Cache-Control", "no-cache,no-store"); req.HttpContext.Response.Headers.Add("Expires", DateTime.Now.AddMinutes(5).ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss G\\MT")); req.HttpContext.Response.Headers.Add("Vary", "Origin"); processClicksQueue.Add(new HttpRequestEntity(req)); return(new RedirectResult(redirect.RedirectTo, true)); }
public static async void ProcessClicksForGeo( [QueueTrigger(QueueNames.ProcessClicksGeo)] string queuedHttpRequestString, [Table(TableNames.Redirects)] CloudTable redirectTable, [Table(TableNames.Domains)] CloudTable domainTable, [Table(TableNames.Geos)] CloudTable geoTable, ILogger log, ExecutionContext context) { HttpRequestEntity queuedHttpRequest = JsonConvert.DeserializeObject <HttpRequestEntity>(queuedHttpRequestString); var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); string ipLookupUrl = $"{config["FREEGEOIP_HOST"] ??= "https://freegeoip.app"}/json/{queuedHttpRequest.RemoteIpAddress}"; log.LogInformation($"Looking up freegeoip: {ipLookupUrl}."); var client = new HttpClient(); var getResponse = await client.GetAsync(ipLookupUrl); if (getResponse.StatusCode == HttpStatusCode.OK) { List <DomainEntity> domains = await DomainEntity.get(domainTable, queuedHttpRequest.Host); if (domains == null) { throw new Exception($"Unable to process Geo lookup - domain {queuedHttpRequest.Host} wasn't found"); } string path = queuedHttpRequest.Path.Value.Substring(1); RedirectEntity redirect = await RedirectEntity.get(redirectTable, domains.First().Account, path); if (redirect != null) { string ipResponseString = await getResponse.Content.ReadAsStringAsync(); dynamic ipResponse = JsonConvert.DeserializeObject <dynamic>(ipResponseString); GeoEntity geoEntity = new GeoEntity(ipResponse); await GeoEntity.put(geoTable, geoEntity); Dictionary <string, int> _geoCount = JsonConvert.DeserializeObject <Dictionary <string, int> >(redirect.GeoCount ??= "{}"); if (_geoCount.ContainsKey(geoEntity.RowKey)) { log.LogInformation($"Incrementing GeoCount for redirect entity {queuedHttpRequest.Path}"); _geoCount[geoEntity.RowKey] = _geoCount[geoEntity.RowKey] + 1; } else { log.LogInformation($"Creating GeoCount for redirect entity {queuedHttpRequest.Path}"); _geoCount.Add(geoEntity.RowKey, 1); } redirect.GeoCount = JsonConvert.SerializeObject(_geoCount); await RedirectEntity.put(redirectTable, redirect); return; } log.LogError($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled path"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled path"); } log.LogError($"Free geo ip lookup for IP {queuedHttpRequest.RemoteIpAddress} failed with status code {getResponse.StatusCode}"); throw new System.Exception($"Free geo ip lookup for IP {queuedHttpRequest.RemoteIpAddress} failed with status code {getResponse.StatusCode}"); }
public ActionResult Delete(RedirectEntity entity) { _redirectService.Delete(int.Parse(entity.Id)); return(RedirectToAction("Index")); }
public static async Task <IActionResult> RunRedirectSession( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "redirect/session/{id}/")] HttpRequest req, [Table(TableNames.Cache)] CloudTable cacheTable, [Table(TableNames.RedirectSessions)] CloudTable sessionRedirectTable, [Queue(QueueNames.ProcessRedirectClicks), StorageAccount("AzureWebJobsStorage")] ICollector <HttpRequestEntity> processRedirectQueue, string id, ILogger log, ExecutionContext context) { id = id ?? req.Query["id"]; int numericId = 0; int.TryParse(id, out numericId); if (numericId > 0) { id = numericId.ToString(); } var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); RedirectEntity redirect = await RedirectEntity.get(sessionRedirectTable, id); Session foundSession = GetSession.ById(await GetSession.GetAllSessions(cacheTable, log, context), id, req, true); if (redirect != null && redirect.RedirectTo != null) { int startRedirectingMinutes = (redirect.StartRedirectingMinutes == null) ? -5 : redirect.StartRedirectingMinutes.Value; if (foundSession != null && foundSession.startsAt != null) { DateTime startRedirecting = foundSession.startsAt.Value.ToUniversalTime().AddMinutes(startRedirectingMinutes); DateTime now = DateTime.Now; if (DateTime.Compare(now, startRedirecting) >= 0) { log.LogInformation($"Start redirecting condition met for {req.Path} - redirect time was {startRedirecting} (current time {now})"); if (req.QueryString.ToString().IndexOf("check") < 0) { processRedirectQueue.Add(new HttpRequestEntity(req)); if (redirect.RedirectTo.StartsWith("/") && redirect.RedirectTo.Substring(1, 1) != "/") { return(new RedirectResult($"{config["REDIRECT_DESTINATION_HOST"]}{redirect.RedirectTo}", false)); } return(new RedirectResult($"{redirect.RedirectTo}", false)); } return(new AcceptedResult()); } else { log.LogInformation($"Start redirecting condition not met for {req.Path} - waiting until {startRedirecting} (current time {now})"); if (req.QueryString.ToString().IndexOf("check") >= 0) { return(new OkObjectResult($"Session found, waiting until {startRedirecting} before redirecting (current time {now})")); } } } else { log.LogInformation($"Start redirecting condition not met for {req.Path} - session has no start time)"); if (req.QueryString.ToString().IndexOf("check") >= 0) { return(new OkObjectResult($"Session found, but has no start time in sessionize")); } } } if (foundSession != null) { if (req.QueryString.ToString().IndexOf("check") >= 0) { return(new OkObjectResult($"Session found, wait for redirect")); } string holdingPageUrl = $"{config["HOLDPAGE_SESSION"]}"; holdingPageUrl = holdingPageUrl.Replace("{id}", foundSession.id ??= string.Empty); int holdpageCacheMinutes = 0; bool foundConfig = int.TryParse(config["HOLDPAGE_CACHE_MINUTES"], out holdpageCacheMinutes); if (!foundConfig) { holdpageCacheMinutes = 10; } CacheEntity cachedSessionPage = await CacheEntity.get(cacheTable, CacheType.Session, $"session-{id}", new TimeSpan(0, holdpageCacheMinutes, 0)); if (cachedSessionPage != null) { string value = cachedSessionPage.GetValue(); return(new ContentResult { ContentType = "text/html; charset=UTF-8", Content = value }); } log.LogInformation($"Looking up holding page content: {holdingPageUrl}."); var client = new HttpClient(); var getResponse = await client.GetAsync(holdingPageUrl); if (getResponse.IsSuccessStatusCode) { string value = await getResponse.Content.ReadAsStringAsync(); int redirectDelay = 10; bool foundRedirectDelay = int.TryParse(config["REDIRECT_DELAY"], out redirectDelay); if (!foundRedirectDelay) { redirectDelay = 10; } value = value.Replace("{title}", foundSession.title ??= string.Empty); value = value.Replace("{description}", foundSession.description ??= string.Empty); value = value.Replace("{id}", foundSession.id ??= string.Empty); value = value.Replace("{url}", foundSession.url ??= string.Empty); value = value.Replace("{ical}", foundSession.ical ??= string.Empty); value = value.Replace("{speakers}", string.Join(", ", foundSession.speakers.Select(speaker => speaker.name))); value = value.Replace("{redirect-js}", Constants.REDIRECT_JS.Replace("{url}", $"{req.Path}?check")).Replace("{redirect-delay}", (redirectDelay * 1000).ToString()); value = value.Replace("{embed-js}", EMBED_JS); if (value.IndexOf("{speaker-profiles}") >= 0) { string speakerData = await GetSpeaker.GetAllSpeakers(cacheTable, log, context); value = value.Replace("{speaker-profiles}", string.Join("", foundSession.speakers.Select(speaker => { SpeakerInformation foundSpeaker = GetSpeaker.ById(speakerData, speaker.id, req, false); return(SpeakerInformation.ProcessSpeakerTokens(Constants.SPEAKER_HTML, foundSpeaker)); }))); } await CacheEntity.put(cacheTable, CacheType.Session, $"session-{id}", value, 600); return(new ContentResult { ContentType = "text/html; charset=UTF-8", Content = value }); } else { return(new NotFoundObjectResult($"{config["HOLDPAGE_SESSION"]} template page not found")); } } return(new NotFoundResult()); }
public static async void ProcessRedirectClicksForGeo( [QueueTrigger(QueueNames.ProcessRedirectClicksForGeo)] string queuedHttpRequestString, [Table(TableNames.RedirectSessions)] CloudTable redirectTable, ILogger log, ExecutionContext context) { HttpRequestEntity queuedHttpRequest = JsonConvert.DeserializeObject <HttpRequestEntity>(queuedHttpRequestString); var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); string ipLookupUrl = $"{config["FREEGEOIP_HOST"] ??= "https://freegeoip.app"}/json/{queuedHttpRequest.RemoteIpAddress}"; log.LogInformation($"Looking up freegeoip: {ipLookupUrl}."); var client = new HttpClient(); var getResponse = await client.GetAsync(ipLookupUrl); if (getResponse.StatusCode == HttpStatusCode.OK) { MatchCollection matches = Regex.Matches(queuedHttpRequest.Path, "/redirect/session/(\\d+)/", RegexOptions.IgnoreCase); if (matches.Count > 0) { string ipResponseString = await getResponse.Content.ReadAsStringAsync(); dynamic ipResponse = JsonConvert.DeserializeObject(ipResponseString); GeoEntity geoEntity = new GeoEntity(ipResponse); string geoEntityString = JsonConvert.SerializeObject(geoEntity); RedirectEntity redirectEntity = await RedirectEntity.get(redirectTable, matches[0].Groups[1].Value); if (redirectEntity != null) { if (redirectEntity.GeoCount == null) { log.LogInformation($"Adding GeoCount property to redirect entity {queuedHttpRequest.Path}"); // redirectEntity.GeoCount = new Dictionary<string, int>(); } Dictionary <string, int> _geoCount = JsonConvert.DeserializeObject <Dictionary <string, int> >(redirectEntity.GeoCount ??= "{}"); if (_geoCount.ContainsKey(geoEntityString)) { log.LogInformation($"Incrementing GeoCount for redirect entity {queuedHttpRequest.Path}"); _geoCount[geoEntityString] = _geoCount[geoEntityString] + 1; } else { log.LogInformation($"Creating GeoCount for redirect entity {queuedHttpRequest.Path}"); _geoCount.Add(geoEntityString, 1); } log.LogInformation($" GeoCount property value: {JsonConvert.SerializeObject(redirectEntity.GeoCount)}"); await RedirectEntity.put(redirectTable, redirectEntity.RowKey, redirectEntity.RedirectTo, redirectEntity.VideoLink, redirectEntity.StartRedirectingMinutes ??= 0, redirectEntity.ClickCount, redirectEntity.CalendarClickCount, redirectEntity.VideoClickCount, JsonConvert.SerializeObject(_geoCount), redirectEntity.CalendarGeoCount, redirectEntity.VideoGeoCount); log.LogInformation($"Successfully processed geo ip click for redirect query {queuedHttpRequest.Path} from {queuedHttpRequest.RemoteIpAddress}"); return; } else { log.LogError($"Http request {queuedHttpRequest.Path} for click geo handling failed to match a redirect session"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click geo handling failed to match a redirect session"); } } MatchCollection calendarMatches = Regex.Matches(queuedHttpRequest.Path, "/calendar/session/(\\d+)", RegexOptions.IgnoreCase); if (calendarMatches.Count > 0) { string ipResponseString = await getResponse.Content.ReadAsStringAsync(); dynamic ipResponse = JsonConvert.DeserializeObject(ipResponseString); GeoEntity geoEntity = new GeoEntity(ipResponse); string geoEntityString = JsonConvert.SerializeObject(geoEntity); RedirectEntity redirectEntity = await RedirectEntity.get(redirectTable, calendarMatches[0].Groups[1].Value); if (redirectEntity != null) { Dictionary <string, int> _calendarGeoCount = JsonConvert.DeserializeObject <Dictionary <string, int> >(redirectEntity.CalendarGeoCount ??= "{}"); if (_calendarGeoCount.ContainsKey(geoEntityString)) { log.LogInformation($"Incrementing CalendarGeoCount for redirect entity {queuedHttpRequest.Path}"); _calendarGeoCount[geoEntityString] = _calendarGeoCount[geoEntityString] + 1; } else { log.LogInformation($"Creating CalendarGeoCount for redirect entity {queuedHttpRequest.Path}"); _calendarGeoCount.Add(geoEntityString, 1); } log.LogInformation($" CalendarGeoCount property value: {JsonConvert.SerializeObject(redirectEntity.GeoCount)}"); await RedirectEntity.put(redirectTable, redirectEntity.RowKey, redirectEntity.RedirectTo, redirectEntity.VideoLink, redirectEntity.StartRedirectingMinutes ??= 0, redirectEntity.ClickCount, redirectEntity.CalendarClickCount, redirectEntity.VideoClickCount, redirectEntity.GeoCount, JsonConvert.SerializeObject(_calendarGeoCount), redirectEntity.VideoGeoCount); log.LogInformation($"Successfully processed calendar geo ip click for redirect query {queuedHttpRequest.Path} from {queuedHttpRequest.RemoteIpAddress}"); return; } else { log.LogError($"Http request {queuedHttpRequest.Path} for click geo handling failed to match a redirect session"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click geo handling failed to match a redirect session"); } } MatchCollection videoMatches = Regex.Matches(queuedHttpRequest.Path, "/redirect/video/(\\d+)/", RegexOptions.IgnoreCase); if (videoMatches.Count > 0) { string ipResponseString = await getResponse.Content.ReadAsStringAsync(); dynamic ipResponse = JsonConvert.DeserializeObject(ipResponseString); GeoEntity geoEntity = new GeoEntity(ipResponse); string geoEntityString = JsonConvert.SerializeObject(geoEntity); RedirectEntity redirectEntity = await RedirectEntity.get(redirectTable, videoMatches[0].Groups[1].Value); if (redirectEntity != null) { Dictionary <string, int> _videoGeoCount = JsonConvert.DeserializeObject <Dictionary <string, int> >(redirectEntity.VideoGeoCount ??= "{}"); if (_videoGeoCount.ContainsKey(geoEntityString)) { log.LogInformation($"Incrementing VideoGeoCount for redirect entity {queuedHttpRequest.Path}"); _videoGeoCount[geoEntityString] = _videoGeoCount[geoEntityString] + 1; } else { log.LogInformation($"Creating VideoGeoCount for redirect entity {queuedHttpRequest.Path}"); _videoGeoCount.Add(geoEntityString, 1); } log.LogInformation($" VideoGeoCount property value: {JsonConvert.SerializeObject(redirectEntity.GeoCount)}"); await RedirectEntity.put(redirectTable, redirectEntity.RowKey, redirectEntity.RedirectTo, redirectEntity.VideoLink, redirectEntity.StartRedirectingMinutes ??= 0, redirectEntity.ClickCount, redirectEntity.CalendarClickCount, redirectEntity.VideoClickCount, redirectEntity.GeoCount, redirectEntity.CalendarGeoCount, JsonConvert.SerializeObject(_videoGeoCount)); log.LogInformation($"Successfully processed video geo ip click for redirect query {queuedHttpRequest.Path} from {queuedHttpRequest.RemoteIpAddress}"); return; } else { log.LogError($"Http request {queuedHttpRequest.Path} for click geo handling failed to match a redirect session"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click geo handling failed to match a redirect session"); } } log.LogError($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled paths"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled paths"); } log.LogError($"Free geo ip lookup for IP {queuedHttpRequest.RemoteIpAddress} failed with status code {getResponse.StatusCode}"); throw new System.Exception($"Free geo ip lookup for IP {queuedHttpRequest.RemoteIpAddress} failed with status code {getResponse.StatusCode}"); }
public static async void ProcessRedirectClicks( [QueueTrigger(QueueNames.ProcessRedirectClicks)] string queuedHttpRequestString, [Table(TableNames.RedirectSessions)] CloudTable redirectTable, [Queue(QueueNames.ProcessRedirectClicksForGeo), StorageAccount("AzureWebJobsStorage")] ICollector <HttpRequestEntity> processRedirectQueueForGeo, ILogger log, ExecutionContext context) { HttpRequestEntity queuedHttpRequest = JsonConvert.DeserializeObject <HttpRequestEntity>(queuedHttpRequestString); var config = new ConfigurationBuilder() .SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); string nodeMaster = config["NODE_SYNC_MASTER_CONN"]; if (nodeMaster != null) { try { CloudStorageAccount storageAccount = CloudStorageAccount.Parse(nodeMaster); CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue destinationProcessClicksQueue = queueClient.GetQueueReference(QueueNames.ProcessRedirectClicks); await destinationProcessClicksQueue.AddMessageAsync(new CloudQueueMessage(queuedHttpRequestString)); } catch (Exception ex) { log.LogError(ex.Message); throw ex; } return; } MatchCollection matches = Regex.Matches(queuedHttpRequest.Path, "/redirect/session/(\\d+)/", RegexOptions.IgnoreCase); if (matches.Count > 0) { RedirectEntity redirectEntity = await RedirectEntity.get(redirectTable, matches[0].Groups[1].Value); if (redirectEntity != null) { redirectEntity.ClickCount++; await RedirectEntity.put(redirectTable, redirectEntity.RowKey, redirectEntity.RedirectTo, redirectEntity.VideoLink, redirectEntity.StartRedirectingMinutes ??= 0, redirectEntity.ClickCount, redirectEntity.CalendarClickCount, redirectEntity.VideoClickCount, redirectEntity.GeoCount, redirectEntity.CalendarGeoCount, redirectEntity.VideoGeoCount); processRedirectQueueForGeo.Add(queuedHttpRequest); log.LogInformation($"Successfully processed click for redirect query {queuedHttpRequest.Path} from {queuedHttpRequest.RemoteIpAddress}"); return; } else { log.LogError($"Http request {queuedHttpRequest.Path} for click handling failed to match a redirect session"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled paths"); } } MatchCollection sessionMatches = Regex.Matches(queuedHttpRequest.Path, "/calendar/session/(\\d+)", RegexOptions.IgnoreCase); if (sessionMatches.Count > 0) { RedirectEntity redirectEntity = await RedirectEntity.get(redirectTable, sessionMatches[0].Groups[1].Value); if (redirectEntity != null) { redirectEntity.CalendarClickCount++; await RedirectEntity.put(redirectTable, redirectEntity.RowKey, redirectEntity.RedirectTo, redirectEntity.VideoLink, redirectEntity.StartRedirectingMinutes ??= 0, redirectEntity.ClickCount, redirectEntity.CalendarClickCount, redirectEntity.VideoClickCount, redirectEntity.GeoCount, redirectEntity.CalendarGeoCount, redirectEntity.VideoGeoCount); processRedirectQueueForGeo.Add(queuedHttpRequest); log.LogInformation($"Successfully processed click for redirect query {queuedHttpRequest.Path} from {queuedHttpRequest.RemoteIpAddress}"); return; } else { log.LogError($"Http request {queuedHttpRequest.Path} for click handling failed to match a redirect session"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click handling failed to match a redirect session"); } } MatchCollection videoMatches = Regex.Matches(queuedHttpRequest.Path, "/redirect/video/(\\d+)/", RegexOptions.IgnoreCase); if (videoMatches.Count > 0) { RedirectEntity redirectEntity = await RedirectEntity.get(redirectTable, videoMatches[0].Groups[1].Value); if (redirectEntity != null) { redirectEntity.VideoClickCount++; await RedirectEntity.put(redirectTable, redirectEntity.RowKey, redirectEntity.RedirectTo, redirectEntity.VideoLink, redirectEntity.StartRedirectingMinutes ??= 0, redirectEntity.ClickCount, redirectEntity.CalendarClickCount, redirectEntity.VideoClickCount, redirectEntity.GeoCount, redirectEntity.CalendarGeoCount, redirectEntity.VideoGeoCount); processRedirectQueueForGeo.Add(queuedHttpRequest); log.LogInformation($"Successfully processed click for redirect query {queuedHttpRequest.Path} from {queuedHttpRequest.RemoteIpAddress}"); return; } else { log.LogError($"Http request {queuedHttpRequest.Path} for click handling failed to match a redirect session"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click handling failed to match a redirect session"); } } log.LogError($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled paths"); throw new System.Exception($"Http request {queuedHttpRequest.Path} for click handling doesn't match handled paths"); }
public DownloadCount(RedirectEntity redirect) { this.Redirect = redirect; }