protected override async Task ExecuteAsync(CancellationToken stoppingToken) { using (var db = new ComeAndTicketContext("come_and_ticket_user", "comeandticket")) { while (!stoppingToken.IsCancellationRequested) { try { _logger.Info("Worker running at: {time}", DateTimeOffset.Now); _logger.Info("Updating Drafthouse data from web"); await ComeAndTicketContext.UpdateDatabaseFromWebAsync(db); _logger.Info("Writing to database"); await db.SaveChangesAsync(); } catch (Exception ex) { _logger.Error(ex, "Exception while updating drafthouse data from web"); } await Task.Delay(TimeSpan.FromMinutes(20)); } } }
static async Task <int> Main(string[] args) { IConfiguration config = new ConfigurationBuilder() .AddUserSecrets("8e048337-f50e-490d-b2a5-5b87d81786fb") .Build(); ConfigureLogging(); IConfigurationSection dbAuthSection = config.GetSection("Authentication:Database"); string userName = dbAuthSection["UserName"]; string password = dbAuthSection["Password"]; using (var db = new ComeAndTicketContext(userName, password)) { try { _logger.Info("Creating database"); if (db.Database.IsSqlite()) { await db.Database.EnsureCreatedAsync(); } else { await db.Database.MigrateAsync(); } return(await RunAndReturnExitCodeAsync(db)); } catch (Exception ex) { _logger.Error(ex, "Exception while running"); return(-1); } } }
private static async Task <int> RunAndReturnExitCodeAsync(ComeAndTicketContext db) { _logger.Info("Updating Drafthouse data from web"); await ComeAndTicketContext.UpdateDatabaseFromWebAsync(db); //await // db.ShowTimes // .Include(s => s.Movie) // .Include(s => s.Theater) // .ThenInclude(t => t.Market) // .LoadAsync(); await PushMoviesAsync(db); return(0); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); IConfigurationSection dbAuthSection = Configuration.GetSection("Authentication:Database"); var context = new ComeAndTicketContext(dbAuthSection["UserName"], dbAuthSection["Password"]); services.AddSingleton <ComeAndTicketContext>(context); services.AddSingleton <IComeAndTicketDataService, ComeAndTicketDataService>(); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); services.AddAuthentication().AddGoogle(options => { IConfigurationSection googleAuthSection = Configuration.GetSection("Authentication:Google"); options.ClientId = googleAuthSection["ClientId"]; options.ClientSecret = googleAuthSection["ClientSecret"]; options.ClaimActions.MapJsonKey("urn:google:profile", "link"); options.ClaimActions.MapJsonKey("urn:google:image", "picture"); }); // From: https://github.com/aspnet/Blazor/issues/1554 // Adds HttpContextAccessor used to determine if a user is logged in and what their username is services.AddHttpContextAccessor(); services.AddScoped <HttpContextAccessor>(); // Required for HttpClient support in the Blazor Client project services.AddHttpClient(); services.AddScoped <HttpClient>(); // Pass settings to other components services.AddSingleton <IConfiguration>(Configuration); }
public ComeAndTicketDataService(ComeAndTicketContext context) { _dbContext = context; }
private static async Task PushMoviesAsync(ComeAndTicketContext db) { var users = await db.Users .Include(u => u.HomeMarket) .Include(u => u.Notifications) .Include(u => u.MovieTitlesToWatch) .Include(u => u.DeviceNicknames) .ToListAsync(); foreach (var user in users) { if (string.IsNullOrEmpty(user.PushbulletApiKey)) { _logger.Warn($"User is not configured with a pushbullet API key: {user.EMail}"); continue; } _logger.Info($"Getting devices from Pushbullet for user {user.EMail}"); var pushbulletApi = new Pushbullet(user.PushbulletApiKey); var retrieveDevicesByNickname = user.DeviceNicknames.Select(async nickname => await pushbulletApi.GetDeviceByNickname(nickname.Value)); var devices = await Task.WhenAll(retrieveDevicesByNickname); if (!devices.Any()) { continue; } _logger.Info($"Finding movies for user {user.EMail}"); var showTimes = await FindMoviesAsync(user, db); IEnumerable <IGrouping <Movie, ShowTime> > moviesOnSale = ( from s in showTimes where MovieTitleContains(s.Movie, user.MovieTitlesToWatch) where !MovieAlreadySent(s, user) where s.TicketsStatus != TicketsStatus.Past select s ).GroupBy( s => s.Movie, MovieComparer.TitleCurrentCultureIgnoreCase); if (!moviesOnSale.Any()) { continue; } var showTimesSent = new List <ShowTime>(); var messageBuilder = new StringBuilder(); messageBuilder.AppendLine(Environment.MachineName); foreach (var movieOnSale in moviesOnSale) { Movie m = movieOnSale.Key; messageBuilder.AppendLine(m.Title); foreach (ShowTime s in movieOnSale) { if (s.TicketsStatus == TicketsStatus.OnSale) { messageBuilder.AppendLine($" - {s.Date} (Left: {s.SeatsLeft} seats, Buy: {s.TicketsUrl} )"); } else if (s.TicketsStatus == TicketsStatus.SoldOut) { messageBuilder.AppendLine($" - {s.Date} (Sold out)"); } else { messageBuilder.AppendLine($" - {s.Date} (Unknown ticket status)"); } showTimesSent.Add(s); } messageBuilder.AppendLine(); } foreach (var device in devices) { await pushbulletApi.PushNoteAsync( "New tickets available", messageBuilder.ToString(), device.Id); } MarkMovieSent(showTimesSent, user); } await db.SaveChangesAsync(); }
private static async Task <IEnumerable <ShowTime> > FindMoviesAsync(User user, ComeAndTicketContext db) { // The database does not support doing a case-insensitive IN operation (to make the // showtime.Movie.Title IN opts.Movies) // So we just get all the movies in the user's market, and then filter further later var partialShowTimes = await db.ShowTimes .Include(st => st.Movie) .Include(st => st.UsersUpdated) .Where(s => s.Theater.Market == user.HomeMarket) .Where(s => s.SeatsLeft > 0) .Where(s => s.TicketsStatus == TicketsStatus.OnSale) .ToArrayAsync(); return(partialShowTimes); }