mirror of
https://git.dirksys.ovh/dirk/bankserver.git
synced 2025-12-20 02:59:20 +01:00
support marking chat messages as read
This commit is contained in:
parent
a6cdd5377b
commit
ec40de6068
@ -12,6 +12,7 @@ use crate::{
|
|||||||
pub struct Chat {
|
pub struct Chat {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub created: DateTime<Utc>,
|
pub created: DateTime<Utc>,
|
||||||
|
pub read_until: Option<Uuid>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "schemas", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemas", derive(schemars::JsonSchema))]
|
||||||
|
|||||||
@ -537,6 +537,38 @@ paths:
|
|||||||
$ref: '#/components/responses/InvalidBody'
|
$ref: '#/components/responses/InvalidBody'
|
||||||
default:
|
default:
|
||||||
$ref: '#/components/responses/Default'
|
$ref: '#/components/responses/Default'
|
||||||
|
/api/chats/{chatId}/messages/{messageId}/read:
|
||||||
|
post:
|
||||||
|
operationId: mark-chat-message-read
|
||||||
|
summary: Mark message as read/unread
|
||||||
|
tags:
|
||||||
|
- Chats
|
||||||
|
security:
|
||||||
|
- bearer: []
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/ChatId'
|
||||||
|
- $ref: '#/components/parameters/MessageId'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ChatMessage'
|
||||||
|
401:
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
403:
|
||||||
|
description: Forbidden
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ApiError'
|
||||||
|
404:
|
||||||
|
$ref: '#/components/responses/ResourceNotFound'
|
||||||
|
422:
|
||||||
|
$ref: '#/components/responses/InvalidBody'
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/Default'
|
||||||
/api/socket:
|
/api/socket:
|
||||||
get:
|
get:
|
||||||
operationId: websocket-events
|
operationId: websocket-events
|
||||||
@ -586,6 +618,13 @@ components:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
MessageId:
|
||||||
|
name: messageId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
PaginationLimit:
|
PaginationLimit:
|
||||||
name: limit
|
name: limit
|
||||||
in: query
|
in: query
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::{Router, extract::Path, routing::get};
|
use axum::{
|
||||||
|
Router,
|
||||||
|
extract::Path,
|
||||||
|
routing::{get, post},
|
||||||
|
};
|
||||||
use bank_core::{
|
use bank_core::{
|
||||||
ApiError,
|
ApiError,
|
||||||
chat::{Chat, ChatInfo, ChatMessage, SendMessage, StartChat},
|
chat::{Chat, ChatInfo, ChatMessage, SendMessage, StartChat},
|
||||||
@ -23,6 +27,7 @@ pub(super) fn router() -> Router<Arc<AppState>> {
|
|||||||
.route("/", get(list_chats).post(create_chat))
|
.route("/", get(list_chats).post(create_chat))
|
||||||
.route("/{id}", get(get_chat))
|
.route("/{id}", get(get_chat))
|
||||||
.route("/{id}/messages", get(get_messages).post(send_message))
|
.route("/{id}/messages", get(get_messages).post(send_message))
|
||||||
|
.route("/{id}/messages/{messageId}/read", post(mark_read))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(state))]
|
#[instrument(skip(state))]
|
||||||
@ -108,3 +113,14 @@ pub async fn send_message(
|
|||||||
}
|
}
|
||||||
Ok(Json(message))
|
Ok(Json(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn mark_read(
|
||||||
|
EState(state): State,
|
||||||
|
auth: Auth,
|
||||||
|
Path((chat_id, message_id)): Path<(Uuid, Uuid)>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut client = state.conn().await?;
|
||||||
|
check_chat(&client, chat_id, auth.user_id()).await?;
|
||||||
|
Chats::mark_read(&mut client, auth.user_id(), chat_id, message_id).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ fn chat_from_row(row: Row) -> Chat {
|
|||||||
Chat {
|
Chat {
|
||||||
id: row.get("id"),
|
id: row.get("id"),
|
||||||
created: row.get("created"),
|
created: row.get("created"),
|
||||||
|
read_until: row.get("read_until"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn chat_info_from_row(row: Row) -> ChatInfo {
|
fn chat_info_from_row(row: Row) -> ChatInfo {
|
||||||
@ -138,6 +139,7 @@ impl Chats {
|
|||||||
Ok(Chat {
|
Ok(Chat {
|
||||||
id,
|
id,
|
||||||
created: result.get(0),
|
created: result.get(0),
|
||||||
|
read_until: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +149,7 @@ impl Chats {
|
|||||||
user: Uuid,
|
user: Uuid,
|
||||||
pagination: RequestPagination,
|
pagination: RequestPagination,
|
||||||
) -> Result<Pagination<Chat>, tokio_postgres::Error> {
|
) -> Result<Pagination<Chat>, tokio_postgres::Error> {
|
||||||
let stmt = client.prepare_cached("select c.id as id, c.created as created from chat_members cm join chats c on cm.chat = c.id where cm.\"user\" = $1 order by c.created desc limit $2 offset $3").await?;
|
let stmt = client.prepare_cached("select c.*, cmru.read_until, array_agg(cm.\"user\") as members from chats c join chat_members cm on cm.chat = c.id join chat_members cmru on cmru.chat = c.id and cmru.\"user\" = $1 where cm.\"user\" = $1 group by c.id, cmru.read_until order by c.created desc limit $2 offset $3").await?;
|
||||||
let count_stmt = client.prepare_cached("select count(c.id) from chat_members cm join chats c on cm.chat = c.id where cm.\"user\" = $1").await?;
|
let count_stmt = client.prepare_cached("select count(c.id) from chat_members cm join chats c on cm.chat = c.id where cm.\"user\" = $1").await?;
|
||||||
let result = client
|
let result = client
|
||||||
.query(&stmt, &[&user, &pagination.limit(), &pagination.offset()])
|
.query(&stmt, &[&user, &pagination.limit(), &pagination.offset()])
|
||||||
@ -207,4 +209,19 @@ impl Chats {
|
|||||||
extra,
|
extra,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn mark_read(
|
||||||
|
client: &mut impl GenericClient,
|
||||||
|
user: Uuid,
|
||||||
|
chat: Uuid,
|
||||||
|
message: Uuid,
|
||||||
|
) -> Result<bool, tokio_postgres::Error> {
|
||||||
|
let stmt = client
|
||||||
|
.prepare_cached(
|
||||||
|
"update chat_members set read_until = $3 where chat = $1 and \"user\" = $2",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let rows = client.execute(&stmt, &[&chat, &user, &message]).await?;
|
||||||
|
Ok(rows == 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,6 +119,54 @@ jsonpath "$.extra" == null
|
|||||||
[Captures]
|
[Captures]
|
||||||
message2: jsonpath "$.id"
|
message2: jsonpath "$.id"
|
||||||
|
|
||||||
|
## Test read status
|
||||||
|
|
||||||
|
GET {{host}}/api/chats/{{chat}}
|
||||||
|
Authorization: Bearer {{user1-token}}
|
||||||
|
HTTP 200
|
||||||
|
[Asserts]
|
||||||
|
jsonpath "$.id" == {{chat}}
|
||||||
|
jsonpath "$.read_until" == null
|
||||||
|
|
||||||
|
GET {{host}}/api/chats/{{chat}}
|
||||||
|
Authorization: Bearer {{user2-token}}
|
||||||
|
HTTP 200
|
||||||
|
[Asserts]
|
||||||
|
jsonpath "$.id" == {{chat}}
|
||||||
|
jsonpath "$.read_until" == null
|
||||||
|
|
||||||
|
|
||||||
|
POST {{host}}/api/chats/{{chat}}/messages/{{message2}}/read
|
||||||
|
Authorization: Bearer {{user2-token}}
|
||||||
|
HTTP 200
|
||||||
|
|
||||||
|
GET {{host}}/api/chats/{{chat}}
|
||||||
|
Authorization: Bearer {{user2-token}}
|
||||||
|
HTTP 200
|
||||||
|
[Asserts]
|
||||||
|
jsonpath "$.id" == {{chat}}
|
||||||
|
jsonpath "$.read_until" == {{message2}}
|
||||||
|
|
||||||
|
|
||||||
|
POST {{host}}/api/chats/{{chat}}/messages/{{message1}}/read
|
||||||
|
Authorization: Bearer {{user2-token}}
|
||||||
|
HTTP 200
|
||||||
|
|
||||||
|
GET {{host}}/api/chats/{{chat}}
|
||||||
|
Authorization: Bearer {{user2-token}}
|
||||||
|
HTTP 200
|
||||||
|
[Asserts]
|
||||||
|
jsonpath "$.id" == {{chat}}
|
||||||
|
jsonpath "$.read_until" == {{message1}}
|
||||||
|
|
||||||
|
|
||||||
|
GET {{host}}/api/chats/{{chat}}
|
||||||
|
Authorization: Bearer {{user1-token}}
|
||||||
|
HTTP 200
|
||||||
|
[Asserts]
|
||||||
|
jsonpath "$.id" == {{chat}}
|
||||||
|
jsonpath "$.read_until" == null
|
||||||
|
|
||||||
# Verify list messages endpoint
|
# Verify list messages endpoint
|
||||||
|
|
||||||
GET {{host}}/api/chats/{{chat}}/messages?limit=50
|
GET {{host}}/api/chats/{{chat}}/messages?limit=50
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user