Skip to content

Commit 732beb5

Browse files
committed
feat: store display name
1 parent 0bbc6d0 commit 732beb5

File tree

7 files changed

+137
-85
lines changed

7 files changed

+137
-85
lines changed

src/adapters/discord/commands/bake.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use serenity::all::{MessageBuilder, UserId};
22
use tracing::error;
33

44
use crate::adapters::discord::{check_is_oracle, Context, Error};
5+
use crate::domain::QueueEntry;
56

67
/// Stek vaffel
78
#[poise::command(
@@ -22,12 +23,12 @@ pub async fn bake(
2223
return Ok(());
2324
}
2425

25-
let mut baked = vec![];
26+
let mut baked: Vec<QueueEntry> = vec![];
2627
let n = ctx.data().queue.size(&guild_id).await.min(amount);
2728

2829
for _ in 0..n {
29-
if let Some(user_id) = ctx.data().queue.pop(&guild_id).await {
30-
baked.push(user_id);
30+
if let Some(entry) = ctx.data().queue.pop(&guild_id).await {
31+
baked.push(entry);
3132
} else {
3233
break;
3334
}
@@ -41,13 +42,13 @@ pub async fn bake(
4142

4243
if baked.len() == 1 {
4344
msg.push(" en vaffel til: ");
44-
let user_id = UserId::new(baked[0].parse::<u64>().unwrap());
45+
let user_id = UserId::new(baked[0].user_id.parse::<u64>().unwrap());
4546
msg.mention(&user_id);
4647
} else {
4748
msg.push(" vafler til: ");
4849

49-
for (i, user_id) in baked.iter().enumerate() {
50-
let user_id = UserId::new(user_id.parse::<u64>().unwrap());
50+
for (i, entry) in baked.iter().enumerate() {
51+
let user_id = UserId::new(entry.user_id.parse::<u64>().unwrap());
5152

5253
if i == baked.len() - 1 {
5354
msg.push(" og ").mention(&user_id);
@@ -60,9 +61,14 @@ pub async fn bake(
6061
msg.build()
6162
};
6263

63-
for user_id in &baked {
64-
if let Err(e) = ctx.data().orders.record_order(user_id, &guild_id).await {
65-
error!("Failed to record order for {user_id}: {e}");
64+
for entry in &baked {
65+
if let Err(e) = ctx
66+
.data()
67+
.orders
68+
.record_order(&entry.user_id, &guild_id)
69+
.await
70+
{
71+
error!("Failed to record order for {}: {e}", entry.user_id);
6672
}
6773
}
6874

src/adapters/discord/commands/queue_size.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub async fn queue(ctx: Context<'_>) -> Result<(), Error> {
1212
}
1313

1414
let user_id = ctx.author().id.to_string();
15-
let message = match ctx.data().queue.index_of(&guild_id, user_id).await {
15+
let message = match ctx.data().queue.index_of(&guild_id, &user_id).await {
1616
Some(index) => format!("😎 Du er {} i køen", index + 1),
1717
None => "🚨 Du er ikke i køen.".to_string(),
1818
};

src/adapters/discord/commands/waffle.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::adapters::discord::{Context, Error};
2+
use crate::domain::QueueEntry;
23

34
/// Få en orakel til å steke vaffel til deg
45
#[poise::command(prefix_command, slash_command, rename = "vaffel")]
@@ -12,14 +13,17 @@ pub async fn waffle(ctx: Context<'_>) -> Result<(), Error> {
1213
}
1314

1415
let user_id = ctx.author().id.to_string();
15-
let message = match ctx.data().queue.index_of(&guild_id, user_id.clone()).await {
16+
let display_name = ctx.author().name.clone();
17+
18+
let message = match ctx.data().queue.index_of(&guild_id, &user_id).await {
1619
Some(index) => format!(
1720
"⏲️ Du er **allerede** i køen. Du er nummer **{}** i køen.",
1821
index + 1
1922
),
2023
None => {
2124
let size = ctx.data().queue.size(&guild_id).await;
22-
ctx.data().queue.push(&guild_id, user_id).await;
25+
let entry = QueueEntry::new(user_id, display_name);
26+
ctx.data().queue.push(&guild_id, entry).await;
2327
format!("⏲️ Du er nå i køen. Du er nummer **{}** i køen.", size + 1)
2428
}
2529
};

src/adapters/http/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use tracing::info;
99

1010
use std::{io, sync::Arc};
1111

12-
use crate::domain::{OrderRepository, QueueRepository};
12+
use crate::domain::{OrderRepository, QueueEntry, QueueRepository};
1313

1414
#[derive(Clone)]
1515
pub struct AppState {
@@ -49,7 +49,7 @@ impl HttpAdapter {
4949
async fn list_queue(
5050
State(state): State<Arc<AppState>>,
5151
Path(guild_id): Path<String>,
52-
) -> Json<Vec<String>> {
52+
) -> Json<Vec<QueueEntry>> {
5353
let queue = state.queue.list(&guild_id).await;
5454
Json(queue)
5555
}

src/domain/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ pub mod order;
22
pub mod queue;
33

44
pub use order::{DailyStats, OrderRepository};
5-
pub use queue::QueueRepository;
5+
pub use queue::{QueueEntry, QueueRepository};

src/domain/queue.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
2+
pub struct QueueEntry {
3+
pub user_id: String,
4+
pub display_name: String,
5+
}
6+
7+
impl QueueEntry {
8+
pub fn new(user_id: String, display_name: String) -> Self {
9+
Self {
10+
user_id,
11+
display_name,
12+
}
13+
}
14+
}
15+
116
#[async_trait::async_trait]
217
pub trait QueueRepository: Send + Sync {
318
/// Open the queue to allow new entries
@@ -9,23 +24,23 @@ pub trait QueueRepository: Send + Sync {
924
/// Check if the queue is currently open
1025
fn is_open(&self, guild_id: &str) -> bool;
1126

12-
/// Find the position of an item in the queue
13-
/// Returns None if the item is not found
14-
async fn index_of(&self, guild_id: &str, target: String) -> Option<usize>;
27+
/// Find the position of a user in the queue by user_id
28+
/// Returns None if the user is not found
29+
async fn index_of(&self, guild_id: &str, user_id: &str) -> Option<usize>;
1530

1631
/// Get the current size of the queue
1732
async fn size(&self, guild_id: &str) -> usize;
1833

19-
/// Add an item to the end of the queue
34+
/// Add a user to the end of the queue
2035
/// Returns the new size of the queue
21-
async fn push(&self, guild_id: &str, value: String) -> usize;
36+
async fn push(&self, guild_id: &str, entry: QueueEntry) -> usize;
2237

23-
/// Remove the item at the front of the queue and return it
38+
/// Remove the entry at the front of the queue and return it
2439
/// Returns None if the queue is empty
25-
async fn pop(&self, guild_id: &str) -> Option<String>;
40+
async fn pop(&self, guild_id: &str) -> Option<QueueEntry>;
2641

27-
/// Get all items in the queue
28-
async fn list(&self, guild_id: &str) -> Vec<String>;
42+
/// Get all entries in the queue
43+
async fn list(&self, guild_id: &str) -> Vec<QueueEntry>;
2944

3045
/// Clear the queue
3146
async fn clear(&self, guild_id: &str);

src/infrastructure/redis_queue_repository.rs

Lines changed: 88 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{collections::HashSet, sync::RwLock};
22

33
use redis::AsyncCommands;
44

5-
use crate::domain::QueueRepository;
5+
use crate::domain::{QueueEntry, QueueRepository};
66

77
fn queue_key(guild_id: &str) -> String {
88
format!("queue:{guild_id}")
@@ -40,63 +40,65 @@ impl QueueRepository for RedisQueueRepository {
4040
self.open_guilds.read().unwrap().contains(guild_id)
4141
}
4242

43-
async fn index_of(&self, guild_id: &str, target: String) -> Option<usize> {
43+
async fn index_of(&self, guild_id: &str, user_id: &str) -> Option<usize> {
4444
let key = queue_key(guild_id);
4545
let mut con = self.redis.get_multiplexed_async_connection().await.ok()?;
4646
let list: Vec<String> = con.lrange(&key, 0, -1).await.ok()?;
4747

48-
list.iter().position(|item| item == &target)
48+
list.iter().position(|json_str| {
49+
serde_json::from_str::<QueueEntry>(json_str)
50+
.map(|entry| entry.user_id == user_id)
51+
.unwrap_or(false)
52+
})
4953
}
5054

5155
async fn size(&self, guild_id: &str) -> usize {
5256
let key = queue_key(guild_id);
53-
let mut con = self
54-
.redis
55-
.get_multiplexed_async_connection()
56-
.await
57-
.ok()
58-
.unwrap();
57+
let mut con = match self.redis.get_multiplexed_async_connection().await {
58+
Ok(con) => con,
59+
Err(_) => return 0,
60+
};
5961
con.llen(&key).await.unwrap_or(0)
6062
}
6163

62-
async fn push(&self, guild_id: &str, value: String) -> usize {
64+
async fn push(&self, guild_id: &str, entry: QueueEntry) -> usize {
6365
let key = queue_key(guild_id);
64-
let mut con = self
65-
.redis
66-
.get_multiplexed_async_connection()
67-
.await
68-
.ok()
69-
.unwrap();
70-
con.rpush(&key, value).await.unwrap_or_default()
66+
let json = serde_json::to_string(&entry).unwrap();
67+
let mut con = match self.redis.get_multiplexed_async_connection().await {
68+
Ok(con) => con,
69+
Err(_) => return 0,
70+
};
71+
con.rpush(&key, json).await.unwrap_or_default()
7172
}
7273

73-
async fn pop(&self, guild_id: &str) -> Option<String> {
74+
async fn pop(&self, guild_id: &str) -> Option<QueueEntry> {
7475
let key = queue_key(guild_id);
7576
let mut con = self.redis.get_multiplexed_async_connection().await.ok()?;
7677
let result: redis::RedisResult<Vec<String>> = con.lpop(&key, None).await;
77-
result.ok().and_then(|mut vec| vec.pop())
78+
result
79+
.ok()
80+
.and_then(|mut vec| vec.pop())
81+
.and_then(|json_str| serde_json::from_str(&json_str).ok())
7882
}
7983

80-
async fn list(&self, guild_id: &str) -> Vec<String> {
84+
async fn list(&self, guild_id: &str) -> Vec<QueueEntry> {
8185
let key = queue_key(guild_id);
82-
let mut con = self
83-
.redis
84-
.get_multiplexed_async_connection()
85-
.await
86-
.ok()
87-
.unwrap();
88-
con.lrange(&key, 0, -1).await.unwrap_or_else(|_| vec![])
86+
let mut con = match self.redis.get_multiplexed_async_connection().await {
87+
Ok(con) => con,
88+
Err(_) => return vec![],
89+
};
90+
let json_list: Vec<String> = con.lrange(&key, 0, -1).await.unwrap_or_else(|_| vec![]);
91+
json_list
92+
.into_iter()
93+
.filter_map(|json_str| serde_json::from_str(&json_str).ok())
94+
.collect()
8995
}
9096

9197
async fn clear(&self, guild_id: &str) {
9298
let key = queue_key(guild_id);
93-
let mut con = self
94-
.redis
95-
.get_multiplexed_async_connection()
96-
.await
97-
.ok()
98-
.unwrap();
99-
let _: () = con.del(&key).await.unwrap_or_default();
99+
if let Ok(mut con) = self.redis.get_multiplexed_async_connection().await {
100+
let _: () = con.del(&key).await.unwrap_or_default();
101+
}
100102
}
101103
}
102104

@@ -157,67 +159,92 @@ mod tests {
157159
#[tokio::test]
158160
async fn test_push_and_pop() {
159161
let queue = setup().await;
162+
let guild = "test-push-and-pop";
163+
queue.clear(guild).await;
160164

161-
queue.push(TEST_GUILD, "foo".to_string()).await;
162-
queue.push(TEST_GUILD, "bar".to_string()).await;
165+
let foo = QueueEntry::new("foo".to_string(), "Foo User".to_string());
166+
let bar = QueueEntry::new("bar".to_string(), "Bar User".to_string());
163167

164-
assert_eq!(queue.size(TEST_GUILD).await, 2);
165-
assert_eq!(queue.index_of(TEST_GUILD, "bar".to_string()).await, Some(1));
168+
queue.push(guild, foo.clone()).await;
169+
queue.push(guild, bar.clone()).await;
166170

167-
let popped = queue.pop(TEST_GUILD).await;
168-
assert_eq!(popped, Some("foo".to_string()));
169-
assert_eq!(queue.size(TEST_GUILD).await, 1);
171+
assert_eq!(queue.size(guild).await, 2);
172+
assert_eq!(queue.index_of(guild, "bar").await, Some(1));
170173

171-
let remaining = queue.list(TEST_GUILD).await;
172-
assert_eq!(remaining, vec!["bar".to_string()]);
174+
let popped = queue.pop(guild).await;
175+
assert_eq!(popped, Some(foo));
176+
assert_eq!(queue.size(guild).await, 1);
177+
178+
let remaining = queue.list(guild).await;
179+
assert_eq!(remaining, vec![bar]);
173180
}
174181

175182
#[tokio::test]
176183
async fn test_list() {
177184
let queue = setup().await;
185+
let guild = "test-list";
186+
queue.clear(guild).await;
187+
188+
let foo = QueueEntry::new("foo".to_string(), "Foo User".to_string());
189+
let bar = QueueEntry::new("bar".to_string(), "Bar User".to_string());
178190

179-
queue.push(TEST_GUILD, "foo".to_string()).await;
180-
queue.push(TEST_GUILD, "bar".to_string()).await;
191+
queue.push(guild, foo.clone()).await;
192+
queue.push(guild, bar.clone()).await;
181193

182-
let list = queue.list(TEST_GUILD).await;
183-
assert_eq!(list, vec!["foo".to_string(), "bar".to_string()]);
194+
let list = queue.list(guild).await;
195+
assert_eq!(list, vec![foo, bar]);
184196
}
185197

186198
#[tokio::test]
187199
async fn test_index_of() {
188200
let queue = setup().await;
201+
let guild = "test-index-of";
202+
queue.clear(guild).await;
189203

190-
queue.push(TEST_GUILD, "foo".to_string()).await;
191-
queue.push(TEST_GUILD, "bar".to_string()).await;
204+
let foo = QueueEntry::new("foo".to_string(), "Foo User".to_string());
205+
let bar = QueueEntry::new("bar".to_string(), "Bar User".to_string());
192206

193-
assert_eq!(queue.index_of(TEST_GUILD, "foo".to_string()).await, Some(0));
194-
assert_eq!(queue.index_of(TEST_GUILD, "bar".to_string()).await, Some(1));
195-
assert_eq!(queue.index_of(TEST_GUILD, "baz".to_string()).await, None);
207+
queue.push(guild, foo).await;
208+
queue.push(guild, bar).await;
209+
210+
assert_eq!(queue.index_of(guild, "foo").await, Some(0));
211+
assert_eq!(queue.index_of(guild, "bar").await, Some(1));
212+
assert_eq!(queue.index_of(guild, "baz").await, None);
196213
}
197214

198215
#[tokio::test]
199216
async fn test_size() {
200217
let queue = setup().await;
218+
let guild = "test-size";
219+
queue.clear(guild).await;
220+
221+
assert_eq!(queue.size(guild).await, 0);
201222

202-
assert_eq!(queue.size(TEST_GUILD).await, 0);
223+
let foo = QueueEntry::new("foo".to_string(), "Foo User".to_string());
224+
let bar = QueueEntry::new("bar".to_string(), "Bar User".to_string());
203225

204-
queue.push(TEST_GUILD, "foo".to_string()).await;
205-
queue.push(TEST_GUILD, "bar".to_string()).await;
226+
queue.push(guild, foo).await;
227+
queue.push(guild, bar).await;
206228

207-
assert_eq!(queue.size(TEST_GUILD).await, 2);
229+
assert_eq!(queue.size(guild).await, 2);
208230
}
209231

210232
#[tokio::test]
211233
async fn test_clear() {
212234
let queue = setup().await;
235+
let guild = "test-clear";
236+
queue.clear(guild).await;
213237

214-
queue.push(TEST_GUILD, "foo".to_string()).await;
215-
queue.push(TEST_GUILD, "bar".to_string()).await;
238+
let foo = QueueEntry::new("foo".to_string(), "Foo User".to_string());
239+
let bar = QueueEntry::new("bar".to_string(), "Bar User".to_string());
216240

217-
assert_eq!(queue.size(TEST_GUILD).await, 2);
241+
queue.push(guild, foo).await;
242+
queue.push(guild, bar).await;
218243

219-
queue.clear(TEST_GUILD).await;
244+
assert_eq!(queue.size(guild).await, 2);
245+
246+
queue.clear(guild).await;
220247

221-
assert_eq!(queue.size(TEST_GUILD).await, 0);
248+
assert_eq!(queue.size(guild).await, 0);
222249
}
223250
}

0 commit comments

Comments
 (0)