added timestamps to messages

This commit is contained in:
2025-12-15 17:33:13 +01:00
parent 68e093f388
commit 5c3cfdafe4
6 changed files with 62 additions and 14 deletions

4
Cargo.lock generated
View File

@@ -1884,6 +1884,7 @@ checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
dependencies = [
"base64",
"bytes",
"chrono",
"crc",
"crossbeam-queue",
"either",
@@ -1961,6 +1962,7 @@ dependencies = [
"bitflags",
"byteorder",
"bytes",
"chrono",
"crc",
"digest",
"dotenvy",
@@ -2003,6 +2005,7 @@ dependencies = [
"base64",
"bitflags",
"byteorder",
"chrono",
"crc",
"dotenvy",
"etcetera",
@@ -2038,6 +2041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
dependencies = [
"atoi",
"chrono",
"flume",
"futures-channel",
"futures-core",

View File

@@ -12,7 +12,7 @@ jsonwebtoken = "9.3.1"
password-hash = "0.5.0"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.143"
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "macros", "uuid"] }
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "macros", "uuid", "chrono"] }
tokio = { version = "1.47.1", features = ["rt-multi-thread", "macros"] }
tower-http = { version = "0.6.6", features = ["cors", "limit"] }
tower_governor = "0.8.0"

View File

@@ -23,6 +23,22 @@ CREATE TABLE IF NOT EXISTS message_ (
id BIGSERIAL PRIMARY KEY,
sender INT REFERENCES user_(id) NOT NULL,
room INT REFERENCES room_(id) NOT NULL,
type VARCHAR(32) NOT NULL,
content TEXT NOT NULL
message_type VARCHAR(32) NOT NULL,
content TEXT NOT NULL,
sent_at TIMESTAMP
);
-- Message timestamp creation
CREATE OR REPLACE FUNCTION create_message_timestamp()
RETURNS trigger
AS $$
BEGIN
NEW.sent_at := CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER insert_message
BEFORE INSERT ON message_
FOR EACH ROW
EXECUTE FUNCTION create_message_timestamp();

View File

@@ -15,7 +15,7 @@ INSERT INTO membership_ (user_id, room) VALUES
(3, 1), -- Carol in General Discussion
(1, 3); -- Alice in Random Memes
INSERT INTO message_ (sender, room, type, content) VALUES
INSERT INTO message_ (sender, room, message_type, content) VALUES
(1, 1, 'text', 'Hey everyone, hows it going?'),
(2, 1, 'text', 'All good! Just trying to get through some work.'),
(3, 1, 'text', 'Hello! How are you guys?'),

View File

@@ -10,11 +10,20 @@ use uuid::Uuid;
use crate::db::{user_id_from_uuid, username_from_uuid};
use crate::{auth::verify_jwt, db::room_id_from_uuid};
#[derive(sqlx::FromRow, serde::Serialize, Debug)]
pub struct MessageRow {
pub sender: String,
pub message_type: String,
pub content: String,
pub sent_at: chrono::NaiveDateTime,
}
#[derive(sqlx::FromRow, serde::Serialize, Debug)]
pub struct Message {
pub sender: String,
pub message_type: String,
pub content: String,
pub sent_at: String,
}
#[derive(serde::Deserialize)]
@@ -54,13 +63,14 @@ async fn list_messages(
));
}
let messages = sqlx::query_as::<_, Message>(
let messages = sqlx::query_as::<_, MessageRow>(
r#"
SELECT
u.username AS sender,
r.uuid AS room,
m.type AS message_type,
m.content
m.message_type,
m.content,
m.sent_at
FROM message_ m
JOIN user_ u ON u.id = m.sender
JOIN room_ r ON r.id = m.room
@@ -79,6 +89,16 @@ async fn list_messages(
)
})?;
let messages: Vec<Message> = messages
.into_iter()
.map(|m| Message {
sender: m.sender,
message_type: m.message_type,
content: m.content,
sent_at: m.sent_at.format("%Y-%m-%d %H:%M:%S").to_string(),
})
.collect();
Ok(Json(messages))
}
@@ -94,17 +114,22 @@ async fn create_message(
let room_id = room_id_from_uuid(&db, room_uuid).await?;
sqlx::query(
"INSERT INTO message_ (sender, room, type, content)
VALUES ($1, $2, $3, $4)",
let sent_at: chrono::NaiveDateTime = sqlx::query_scalar(
"INSERT INTO message_ (sender, room, message_type, content)
VALUES ($1, $2, $3, $4) RETURNING sent_at",
)
.bind(user_id)
.bind(room_id)
.bind(&payload.message_type)
.bind(&payload.content)
.execute(&db)
.fetch_one(&db)
.await
.map_err(|_| (StatusCode::BAD_REQUEST, format!("Could not create message")))?;
.map_err(|e| {
(
StatusCode::BAD_REQUEST,
format!("Could not create message: {e}"),
)
})?;
let sender_name = username_from_uuid(&db, claims.sub).await?;
@@ -114,6 +139,7 @@ async fn create_message(
sender: sender_name,
message_type: payload.message_type,
content: payload.content,
sent_at: sent_at.format("%Y-%m-%d %H:%M:%S").to_string(),
}),
))
}

View File

@@ -150,7 +150,9 @@ pub async fn register_user(
))
}
async fn validate_token(headers: HeaderMap) -> Result<String, (StatusCode, String)> {
async fn validate_token(
headers: HeaderMap,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
let _ = verify_jwt(headers)?;
Ok(String::from("OK"))
Ok(Json(serde_json::json!({"valid": true})))
}