/ InfoService.cs
InfoService.cs
  1  using _5uhr.Data;
  2  using Discord;
  3  using Discord.WebSocket;
  4  using Microsoft.EntityFrameworkCore;
  5  
  6  namespace _5uhr;
  7  
  8  public class InfoService(DiscordSocketClient client, IServiceProvider serviceProvider, ILogger<InfoService> logger)
  9  {
 10      public void UpdateInfoAsync()
 11      {
 12          Task.Run(async () =>
 13              {
 14                  try
 15                  {
 16                      await using var scope = serviceProvider.CreateAsyncScope();
 17                      await using var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
 18                      var ts = DateTime.UtcNow;
 19                      var day = await RegistrationModule.GetGangDay(db, ts);
 20                      var nextDay = await RegistrationModule.GetGangDay(db, ts.AddDays(1));
 21                      var mainConfig = await db.Configurations
 22                          .Where(x => x.GuildId == DiscordBotService.MAIN_GUILD_ID)
 23                          .SingleOrDefaultAsync();
 24  
 25                      if (mainConfig == null)
 26                      {
 27                          logger.LogError("No main config!!");
 28                      }
 29  
 30                      var guild = client.GetGuild(DiscordBotService.MAIN_GUILD_ID);
 31                      var leaderboardChannel = guild.GetTextChannel(mainConfig!.LeaderboardChannelId);
 32                      var checkinChannel = guild.GetTextChannel(mainConfig.CheckInChannelId);
 33  
 34                      var leaderboardMessageR =
 35                          (await leaderboardChannel.GetPinnedMessagesAsync()).FirstOrDefault(x =>
 36                              x.Author.Id == client.CurrentUser.Id);
 37                      Embed[] embeds = await GetLeaderboardEmbed(db);
 38                      if (leaderboardMessageR is not null)
 39                      {
 40                          var leaderboardMessage =
 41                              (await leaderboardChannel.GetMessageAsync(leaderboardMessageR.Id)) as IUserMessage;
 42                          logger.LogInformation("Existing message found {LeaderboardMessageId}. Updating.",
 43                              leaderboardMessage?.Id);
 44                          await leaderboardMessage!.ModifyAsync(x => { x.Embeds = embeds; });
 45                      }
 46                      else
 47                      {
 48                          logger.LogInformation("No existing message found. Sending new one to {Channel}.",
 49                              leaderboardChannel.Mention);
 50                          var message = await leaderboardChannel.SendMessageAsync(embeds: embeds);
 51                          // var message = await leaderboardChannel.SendMessageAsync("Deine fucking mutter");
 52                          await message.PinAsync();
 53                      }
 54  
 55                      var dayInfo = await db.Days
 56                          .Where(x => x.Id == day.Id)
 57                          .Select(x => new
 58                          {
 59                              MissingPreCheckIns = x.PreCheckIns.Where(p =>
 60                                  x.CheckIns.All(c => c.MemberThatCheckedIn.Id != p.MemberThatPreCheckedIn.Id)).ToList(),
 61                          })
 62                          .SingleAsync();
 63  
 64                      var tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
 65                      var localTime = TimeZoneInfo.ConvertTime(ts, tz);
 66  
 67                      if (localTime.Hour >= 4)
 68                      {
 69                          var message4 = "AUFSTEHEN! Es ist 4 Uhr! ⏰🌅\n" +
 70                                         "Klicke auf den Button unten, um deinen Check-In zu bestätigen und deinen Tag richtig zu starten! 💪☕\n";
 71  
 72                          var missing4 = dayInfo.MissingPreCheckIns.Where(x => x.ClaimedCheckpoint == TimeCheckpoint.Uhr4)
 73                              .ToList();
 74                          if (missing4.Count > 0)
 75                          {
 76                              message4 += "Es fehlen noch:\n - "
 77                                          + String.Join("\n - ",
 78                                              missing4.Select(x => $"<@{x.MemberThatPreCheckedIn.DiscordUserId}>"));
 79  
 80                              if (localTime.Hour > 4 || localTime.Minute > 10)
 81                              {
 82                                  message4 += "\n\n AN ALLE: Die fehlenden jetzt aus dem Bett schmeissen!";
 83                              }
 84                          }
 85  
 86                          if (!day.MessageForCheckIn4.HasValue)
 87                          {
 88                              var message = await checkinChannel.SendMessageAsync(message4,
 89                                  components: new ComponentBuilder()
 90                                      .AddRow(new ActionRowBuilder()
 91                                          .AddComponent(new ButtonBuilder()
 92                                              .WithStyle(ButtonStyle.Primary)
 93                                              .WithLabel("Check-In - 4 Uhr")
 94                                              .WithCustomId("checkin_button_4:" + day.Id)))
 95                                      .Build());
 96                              day.MessageForCheckIn4 = message.Id;
 97                          }
 98                          else
 99                          {
100                              await checkinChannel.ModifyMessageAsync(day.MessageForCheckIn4.Value,
101                                  x => { x.Content = message4; });
102                          }
103                      }
104  
105                      if (localTime.Hour >= 5)
106                      {
107                          var message5 = "AUFSTEHEN! Es ist 5 Uhr! ⏰🌅\n" +
108                                         "Klicke auf den Button unten, um deinen Check-In zu bestätigen und deinen Tag richtig zu starten! 💪☕\n";
109  
110                          var missing5 = dayInfo.MissingPreCheckIns.Where(x => x.ClaimedCheckpoint == TimeCheckpoint.Uhr5)
111                              .ToList();
112                          if (missing5.Count > 0)
113                          {
114                              message5 += "Es fehlen noch:\n - "
115                                          + String.Join("\n - ",
116                                              missing5.Select(x => $"<@{x.MemberThatPreCheckedIn.DiscordUserId}>"));
117  
118                              if (localTime.Hour > 5 || localTime.Minute > 10)
119                              {
120                                  message5 += "\n\n AN ALLE: Die fehlenden jetzt aus dem Bett schmeissen!";
121                              }
122                          }
123  
124                          if (!day.MessageForCheckIn5.HasValue)
125                          {
126                              var message = await checkinChannel.SendMessageAsync(message5,
127                                  components: new ComponentBuilder()
128                                      .AddRow(new ActionRowBuilder()
129                                          .AddComponent(new ButtonBuilder()
130                                              .WithStyle(ButtonStyle.Primary)
131                                              .WithLabel("Check-In - 5 Uhr")
132                                              .WithCustomId("checkin_button_5:" + day.Id)))
133                                      .Build());
134                              day.MessageForCheckIn5 = message.Id;
135                          }
136                          else
137                          {
138                              await checkinChannel.ModifyMessageAsync(day.MessageForCheckIn5.Value,
139                                  x => { x.Content = message5; });
140                          }
141                      }
142  
143                      if (localTime.Hour >= 12)
144                      {
145                          var messageText =
146                              "12Uhr geschafft. Bitte denkt dran andere zu verifizieren / zu reporten. 👍\n" +
147                              "Ab jetzt kann sich hier für morgen vorregistriert werden.\n";
148  
149                          var infos = await db.Days
150                              .Where(x => x.Id == nextDay.Id)
151                              .Select(x => new
152                              {
153                                  PreCheckIns = x.PreCheckIns
154                                      .OrderBy(p => p.Timestamp)
155                                      .Select(p => new
156                                      {
157                                          p.MemberThatPreCheckedIn,
158                                          p.ClaimedCheckpoint
159                                      }),
160                                  Midnight = x.Start,
161                              })
162                              .SingleAsync();
163  
164                          messageText += String.Join('\n', infos.PreCheckIns.Select(x =>
165                          {
166                              var mention = x.MemberThatPreCheckedIn.DiscordUserId.HasValue
167                                  ? $"<@{x.MemberThatPreCheckedIn.DiscordUserId}>"
168                                  : x.MemberThatPreCheckedIn.FriendlyName ?? "???";
169                              return $"- {mention} um {(x.ClaimedCheckpoint == TimeCheckpoint.Uhr4 ? "4" : "5")} Uhr";
170                          }));
171  
172                          if (!nextDay.MessageForPreCheckInsId.HasValue)
173                          {
174                              var message = await checkinChannel.SendMessageAsync(messageText,
175                                  components: new ComponentBuilder()
176                                      .AddRow(new ActionRowBuilder()
177                                          .AddComponent(new ButtonBuilder()
178                                              .WithStyle(ButtonStyle.Primary)
179                                              .WithLabel("Vorregistrieren - 4 Uhr")
180                                              .WithCustomId("precheckin_button_4:" + nextDay.Id))
181                                          .AddComponent(new ButtonBuilder()
182                                              .WithStyle(ButtonStyle.Primary)
183                                              .WithLabel("Vorregistrieren - 5 Uhr")
184                                              .WithCustomId("precheckin_button_5:" + nextDay.Id)))
185                                      .Build());
186                              nextDay.MessageForPreCheckInsId = message.Id;
187                          }
188                          else
189                          {
190                              await checkinChannel.ModifyMessageAsync(nextDay.MessageForPreCheckInsId.Value,
191                                  x => { x.Content = messageText; });
192                          }
193                      }
194                      await db.SaveChangesAsync();
195                  }
196                  catch (Exception e)
197                  {
198                      logger.LogError("During refreshing info: {Exception}", e);
199                  }
200              }
201          );
202      }
203  
204      private async Task<Embed[]> GetLeaderboardEmbed(ApplicationDbContext db)
205      {
206          var leaderboard = (await Task.WhenAll((await db.Member
207                  .Select(x => new
208                  {
209                      x.DiscordUserId, x.FriendlyName,
210                      Uhr4 = x.CheckIns
211                          .Where(c => c.Verifications.Count > c.Reports.Count)
212                          .Where(c => c.ClaimedCheckpoint == TimeCheckpoint.Uhr4)
213                          .Count()
214                             + x.ImportedCheckIns4Uhr,
215                      Uhr5 = x.CheckIns
216                          .Where(c => c.Verifications.Count > c.Reports.Count)
217                          .Where(c => c.ClaimedCheckpoint == TimeCheckpoint.Uhr5)
218                          .Count()
219                              + x.ImportedCheckIns5Uhr,
220                  })
221                  .Select(x => new
222                  {
223                      x.Uhr4,
224                      x.Uhr5,
225                      x.DiscordUserId,
226                      x.FriendlyName,
227                      Groschen = x.Uhr4 * 2 + x.Uhr5 * 1
228                  })
229                  .Where(x => x.Groschen > 0)
230                  .OrderByDescending(x => x.Groschen)
231                  .ToListAsync())
232              .Select(async x => new
233              {
234                  x.Uhr4,
235                  x.Uhr5,
236                  DiscordUser = x.DiscordUserId.HasValue
237                      ? await client.GetUserAsync(x.DiscordUserId.Value)
238                      : null,
239                  x.FriendlyName,
240                  x.Groschen,
241              })))
242              .Index()
243              .ToArray();
244  
245          if (leaderboard.Length == 0)
246              return [];
247  
248          return
249          [
250              new EmbedBuilder()
251                  .WithTitle("Groschen(G) Leaderboard")
252                  .WithCurrentTimestamp()
253                  .AddField("#", String.Join('\n', leaderboard.Select(x => x.Index)), true)
254                  .AddField("Name", String.Join('\n', leaderboard.Select(x => x.Item.DiscordUser?.Mention ?? x.Item.FriendlyName ?? "???")), true)
255                  .AddField("G", String.Join('\n', leaderboard.Select(x => x.Item.Groschen)), true)
256                  .Build(),
257              new EmbedBuilder()
258                  .WithTitle("# Aufgestanden um 4/5 Uhr")
259                  .WithCurrentTimestamp()
260                  .AddField("Name", String.Join('\n',leaderboard.Select(x => x.Item.DiscordUser?.Mention ?? x.Item.FriendlyName ?? "???")), true)
261                  .AddField("4", String.Join('\n', leaderboard.Select(x => x.Item.Uhr4)), true)
262                  .AddField("5", String.Join('\n', leaderboard.Select(x => x.Item.Uhr5)), true)
263                  .Build()
264          ];
265      }
266  
267      // private async Task<MessageComponent> GetLeaderboardComponents(ApplicationDbContext db)
268      // {
269      //     var leaderboard = (await db.Member
270      //             .Select(x => new
271      //             {
272      //                 x.DiscordUserId, x.FriendlyName,
273      //                 Groschen = x.CheckIns.Count(c => c.Verifications.Count > c.Reports.Count)
274      //             })
275      //             .Where(x => x.Groschen > 0)
276      //             .OrderByDescending(x => x.Groschen)
277      //             .ToListAsync())
278      //         .Index();
279      //
280      //     // markdown table
281      //     var leaderboardTable = """
282      //                            | Range | Name | Groschen |
283      //                            |-------|------|----------|
284      //                            
285      //                            """
286      //                            + String.Join('\n', leaderboard.Select(x =>
287      //                            {
288      //                                string mention;
289      //                                if (x.Item.DiscordUserId.HasValue)
290      //                                {
291      //                                    mention = client.GetUser(x.Item.DiscordUserId.Value).Mention;
292      //                                }
293      //                                else if (x.Item.FriendlyName is not null)
294      //                                {
295      //                                    mention = x.Item.FriendlyName;
296      //                                }
297      //                                else
298      //                                {
299      //                                    mention = "???";
300      //                                }
301      //
302      //                                return $"| {x.Index + 1} | {mention} | {x.Item.Groschen} |";
303      //                            }));
304      //     return
305      //         new ComponentBuilderV2()
306      //             .AddComponent(new TextDisplayBuilder()
307      //                 .WithContent(leaderboardTable))
308      //             .Build();
309      // }
310  }