/ src / matrix / commands / aoc / solutions.rs
solutions.rs
 1  use std::{cmp::Reverse, collections::HashMap, fmt::Write};
 2  
 3  use matrix_sdk::{Room, ruma::events::room::message::OriginalRoomMessageEvent};
 4  
 5  use crate::{
 6      Context,
 7      aoc::{day::AocDay, models::PrivateLeaderboardMember},
 8      matrix::{
 9          commands::CommandResult,
10          utils::{RoomExt, html_message},
11      },
12  };
13  
14  pub async fn invoke(
15      event: &OriginalRoomMessageEvent,
16      room: &Room,
17      context: &Context,
18  ) -> CommandResult<()> {
19      let aoc_users = context
20          .aoc_client
21          .get_private_leaderboard(AocDay::most_recent().year)
22          .await?
23          .0
24          .members
25          .into_values()
26          .map(|u| (u.id, u))
27          .collect::<HashMap<_, _>>();
28  
29      let mut solutions = String::from(
30          r#"
31  <h3>Advent of Code Solution Repositories</h3>
32  <table>
33  <tr> <th>AoC Name</th> <th>Matrix User</th> <th>Repository</th> </tr>
34  "#,
35      );
36  
37      let mut rows = Vec::new();
38  
39      for user in &context.config.users {
40          let Some(repo) = &user.repo else { continue };
41  
42          let aoc_user = user.aoc.and_then(|id| aoc_users.get(&id));
43  
44          let name = aoc_user.map(|u| u.display_name()).unwrap_or_default();
45  
46          let matrix_name = user
47              .matrix
48              .as_ref()
49              .map(|m| m.matrix_to_uri().to_string())
50              .unwrap_or_default();
51  
52          let repo_title = context
53              .config
54              .aoc
55              .repo_rules
56              .match_and_replace(repo)
57              .map(|m| m.replacement);
58  
59          rows.push((aoc_user, name, matrix_name, repo, repo_title));
60      }
61  
62      rows.sort_unstable_by(|a, b| {
63          fn key<'a>(
64              aoc_user: Option<&'a PrivateLeaderboardMember>,
65              name: &'a str,
66          ) -> impl Ord + use<'a> {
67              (Reverse(aoc_user.map(Reverse)), name)
68          }
69          key(a.0, &a.1).cmp(&key(b.0, &b.1))
70      });
71  
72      for (_, name, matrix_name, repo, repo_title) in rows {
73          let repo_title = repo_title.as_deref().unwrap_or(repo);
74          let link_prefix = &context.config.matrix.link_prefix;
75          write!(
76              &mut solutions,
77              r#"
78  <tr>
79      <td>{name}</td>
80      <td>{matrix_name}</td>
81      <td><a href="{link_prefix}{repo}">{repo_title}</a></td>
82  </tr>
83  "#
84          )
85          .unwrap();
86      }
87  
88      solutions.push_str("</table>");
89  
90      room.reply_to(event, html_message(solutions)).await?;
91  
92      Ok(())
93  }