using Scalar.AspNetCore; using Microsoft.AspNetCore.OpenApi; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using System.DirectoryServices.Protocols; using System.Runtime.CompilerServices; SignalIntegration.Instance = new SignalIntegration(AppConfiguration.Instance.SignalAPIEndpointUri, int.Parse(AppConfiguration.Instance.SignalAPIEndpointPort), AppConfiguration.Instance.HostPhoneNumber); LdapIntegration.Instance = new LdapIntegration(AppConfiguration.Instance.LDAPConfig.LDAPserver, AppConfiguration.Instance.LDAPConfig.Port, AppConfiguration.Instance.LDAPConfig.Username, AppConfiguration.Instance.LDAPConfig.Password); var builder = WebApplication.CreateBuilder(args); Console.WriteLine("Setting up user check timer"); var userCheckTimer = new CronTimer("*/1 * * * *", "Europe/Vienna", includingSeconds: false); userCheckTimer.OnOccurence += async (s, ea) => { var memberList = await SignalIntegration.Instance.GetMemberListAsync(); var dci = DataContext.Instance; var needsSaving = false; foreach (var memberId in memberList) { Console.WriteLine("found member: " + memberId); var foundUser = dci.Users.Where(u => u.SignalMemberId == memberId).SingleOrDefault(); if (foundUser == null) { var newUserContact = await SignalIntegration.Instance.GetContactAsync(memberId); Console.WriteLine("New user:"); Console.WriteLine($" Name: {newUserContact.Name}"); Console.WriteLine($" MemberId: {memberId}"); User newUser = new User() { Name = newUserContact.Name, SignalMemberId = memberId, NickName = string.Empty, IsIntroduced = false, LdapUserName = string.Empty, AssociationInProgress = false, }; dci.Users.Add(newUser); needsSaving = true; } } if (needsSaving) { await dci.SaveChangesAsync(); } await dci.DisposeAsync(); }; userCheckTimer.Start(); Console.WriteLine("Setting up user intro timer"); var userIntroTimer = new CronTimer("*/1 * * * *", "Europe/Vienna", includingSeconds: false); userIntroTimer.OnOccurence += async (s, ea) => { var dci = DataContext.Instance; var introUsers = dci.Users.Where(u => !u.IsIntroduced); bool needsSaving = false; foreach (var user in introUsers) { await SignalIntegration.Instance.IntroduceUserAsync(user); user.IsIntroduced = true; needsSaving = true; } if (needsSaving) { await dci.SaveChangesAsync(); } await dci.DisposeAsync(); }; userIntroTimer.Start(); Console.WriteLine("Setting up pick of the day timer"); var pickOfTheDayTimer = new CronTimer("0 8 * * *", "Europe/Vienna", includingSeconds: false); pickOfTheDayTimer.OnOccurence += async (s, ea) => { var rand = new Random(); var num = rand.NextInt64(); var mod = num % AppConfiguration.Instance.AverageDaysBetweenRequests; if (mod > 0) { Console.WriteLine("Skipping pick of the day today!"); return; } var dci = DataContext.Instance; var luckyUser = await dci.Users.ElementAtAsync((new Random()).Next(await dci.Users.CountAsync())); var userName = string.IsNullOrEmpty(luckyUser.NickName) ? luckyUser.Name : luckyUser.NickName; SignalIntegration.Instance.SendMessageToGroupAsync($"Today's chosen person to share a song is: **{userName}**"); SignalIntegration.Instance.SendMessageToUserAsync($"Congratulations, you have been chosen to share a song today!", luckyUser.SignalMemberId); var suggestion = await dci.SuggestionHelpers.ElementAtAsync((new Random()).Next(await dci.SuggestionHelpers.CountAsync())); SignalIntegration.Instance.SendMessageToUserAsync($"Today's (optional) suggestion helper to help you pick a song is:\n\n**{suggestion.Title}**\n\n*{suggestion.Description}*", luckyUser.SignalMemberId); SignalIntegration.Instance.SendMessageToUserAsync($"For now please just share your suggestion with the group - in the future I might ask you to share directly with me or via the website to help me keep track of past suggestions!", luckyUser.SignalMemberId); }; pickOfTheDayTimer.Start(); var startUserAssociationProcess = (User userToAssociate) => { SignalIntegration.Instance.SendMessageToUserAsync($"Hi, I see you are not associated with any website user yet.", userToAssociate.SignalMemberId); SignalIntegration.Instance.SendMessageToUserAsync($"If you haven't yet, please navigate to https://users.disi.dev to create a new account.", userToAssociate.SignalMemberId); SignalIntegration.Instance.SendMessageToUserAsync($"Once you have done so, go to https://sotd.disi.dev, login, navigate to \"Unclaimed Phone Numbers\" and click on the \"Claim\" button to start the claim process.", userToAssociate.SignalMemberId); SignalIntegration.Instance.SendMessageToUserAsync($"With a future update you will be required to submit songs via your user account - at that point you will be skipped during the selection process if you have not yet claimed your phone number!", userToAssociate.SignalMemberId); }; Console.WriteLine("Setting up LdapAssociation timer"); var ldapAssociationTimer = new CronTimer("*/10 * * * *", "Europe/Vienna", includingSeconds: false); ldapAssociationTimer.OnOccurence += async (s, ea) => { var dci = DataContext.Instance; var nonAssociatedUsers = dci.Users.Where(u => string.IsNullOrEmpty(u.LdapUserName) && !u.AssociationInProgress); var needsSaving = false; foreach (var user in nonAssociatedUsers) { user.AssociationInProgress = true; startUserAssociationProcess(user); user.IsIntroduced = true; needsSaving = true; } if (needsSaving) { await dci.SaveChangesAsync(); } await dci.DisposeAsync(); }; ldapAssociationTimer.Start(); var searchResults = LdapIntegration.Instance.SearchInAD( AppConfiguration.Instance.LDAPConfig.LDAPQueryBase, $"(memberOf={AppConfiguration.Instance.LDAPConfig.CrewGroup})", SearchScope.Subtree ); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddOpenApi(); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Auth/Login"; }); builder.Services.AddSingleton(); builder.Services.AddSingleton(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } else { app.MapOpenApi(); app.MapScalarApiReference(); } app.UseRouting(); app.UseAuthorization(); app.MapStaticAssets(); app.MapRazorPages() .WithStaticAssets(); app.MapControllerRoute( name: "login", pattern: "{controller=Auth}/{action=Login}" ); app.MapControllerRoute( name: "logout", pattern: "{controller=Auth}/{action=Logout}" ); app.MapGet("/debug/routes", (IEnumerable endpointSources) => string.Join("\n", endpointSources.SelectMany(source => source.Endpoints))); app.Run();