public async Task NextStage(Incident incident) { incident.WentToVoicemail = false; var stage = CallSequence[incident.Index]; if (stage.Attempts > 1 && incident.Attempt < stage.Attempts) { incident.Attempt++; await StatusHub.UpdateClientAsync(incident.UserId, "phoneDelay", stage.Delay.ToString(), HttpContext); await Task.Delay(stage.Delay * 1000); } else { incident.Index++; incident.Attempt = 1; if (incident.Index >= CallSequence.Count) { await StatusHub.UpdateClientAsync(incident.UserId, "phoneFail", null, HttpContext); return; } stage = CallSequence[incident.Index]; } var phoner = new Phoner(); await phoner.CallAsync(incident, stage, Configuration["Twilio:FromNumber"], HttpContext); }
public async Task <IActionResult> Post(string studentName, string room, int priority) { if (string.IsNullOrWhiteSpace(studentName) || string.IsNullOrWhiteSpace(room) || priority < 1 || priority > 2) { return(StatusCode(500, "Invalid inputs.")); } if (!BritishTime.IsSchoolHours()) { return(StatusCode(500, "This service is unavailable out of hours.")); } var userId = User.Identity.GetUserId(); var incident = new Incident(Guid.NewGuid().ToString("D"), studentName.Split(',')[0].ToTitleCase(), room, User.Identity.Name, userId); if (priority == 1) { Cache.Set(incident.Id, incident, TimeSpan.FromMinutes(20)); var phoner = new Phoner(); await phoner.CallAsync(incident, CallSequence[0], Configuration["Twilio:FromNumber"], HttpContext); } var mailer = new Mailer(Configuration["Email:SenderEmail"], Configuration["Email:SenderPassword"], Configuration["Email:To"], Configuration["Email:Bcc"]); await mailer.SendAsync(studentName, room, User.Identity.Name, priority, User.Identity.GetEmail()); await StatusHub.UpdateClientAsync(userId, "emailSent", priority, HttpContext); return(new EmptyResult()); }
public OverseerBootstrapper(IDataContext context) { _context = context; var applicationSettings = _context.GetApplicationSettings(); _monitoringService = new MonitoringService(applicationSettings.Interval, () => { var providerManager = Container.Resolve <PrinterProviderManager>(); return(providerManager.GetPrinterProviders()); }); _monitoringService.StatusUpdate += (sender, args) => { StatusHub.PushStatusUpdate(args.Status); }; }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, OverseerBootstrapper bootstrapper, IHubContext <StatusHub> statusHub) { bootstrapper.Container.Register <Action <MachineStatus> >((c, n) => { return(status => StatusHub.PushStatusUpdate(statusHub, status)); }); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSpaStaticFiles(); app.Map("/api", builder => { builder.UseAuthentication(); builder.UseOwin(owin => owin.UseNancy(options => options.Bootstrapper = bootstrapper)); }); app.Map("/push", builder => { builder.UseSignalR(routes => { routes.MapHub <StatusHub>("/status"); }); }); app.UseSpa(spa => { if (env.IsDevelopment()) { spa.Options.SourcePath = "../OverseerUI"; spa.UseAngularCliServer(npmScript: "start"); } else { spa.Options.SourcePath = "/OverseerUI"; } }); }
public async Task <IActionResult> StatusCallback(string incidentId, string callStatus) { if (incidentId == null || !Cache.TryGetValue(incidentId, out Incident incident)) { return(StatusCode(401, "Incident token not recognised.")); } if (incident.Index > -1) { var stage = CallSequence[incident.Index]; if (callStatus == "busy" || callStatus == "no-answer" || callStatus == "failed" || callStatus == "canceled" || incident.WentToVoicemail || stage.RequireKeyPress) { await NextStage(incident); } else { incident.Index = -1; await StatusHub.UpdateClientAsync(incident.UserId, "phoneDone", null, HttpContext); } } return(Content("Handled.", "text/plain")); }
public async Task <IActionResult> KeyPress(string incidentId, string callStatus, string digits) { if (incidentId == null || !Cache.TryGetValue(incidentId, out Incident incident)) { return(StatusCode(401, "Incident token not recognised.")); } if (digits == "1") { incident.Index = -1; await StatusHub.UpdateClientAsync(incident.UserId, "phoneDone", null, HttpContext); var response = new VoiceResponse() .Say($"Thank you for agreeing to support in {incident.Room}.", Say.VoiceEnum.Woman) .Pause(1) .Say("Goodbye.", Say.VoiceEnum.Woman) .Hangup(); return(Content(response.ToString(), "text/xml")); } else { return(Index(incidentId, "human")); } }
public static void Start(string endpoint, OverseerBootstrapper bootstrapper) { Log.Info("Starting Server..."); bootstrapper.Container.Register <StatusHubService>(); bootstrapper.Container.Register <Action <MachineStatus> >(s => StatusHub.PushStatusUpdate(s)); GlobalHost.DependencyResolver.Register(typeof(StatusHub), () => { return(bootstrapper.Container.Resolve <StatusHub>()); }); GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => { return(new JsonSerializer { ContractResolver = new OverseerContractResolver(), Formatting = Formatting.None }); }); WebApp.Start(endpoint, app => { app.UseOverseerAuthentication(bootstrapper.Container); app.MapSignalR("/push", new HubConfiguration { EnableDetailedErrors = true, EnableJavaScriptProxies = true, EnableJSONP = false }); app.Map("/api", a => { a.UseNancy(new NancyOptions { Bootstrapper = bootstrapper }); }); /* * This is needed to support client side routing without the use of hash bang urls. * If the request wasn't for a file, an api request, or a signalr request then redirect to the root to be handled by index.html */ app.Use(async(IOwinContext context, Func <Task> next) => { await next.Invoke(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/push") && !context.Request.Path.Value.StartsWith("/api")) { context.Request.Path = new PathString("/index.html"); await next.Invoke(); } }); app.UseFileServer(new FileServerOptions { EnableDirectoryBrowsing = false, EnableDefaultFiles = true, DefaultFilesOptions = { DefaultFileNames = { "index.html" } }, FileSystem = new PhysicalFileSystem(ClientPath), StaticFileOptions = { ContentTypeProvider = new OverseerContentTypeProvider() } }); }); Log.Info($"Listening at {endpoint}..."); }