generated from t/malachite
add: working chat ui
This commit is contained in:
parent
f53eb3d367
commit
b360c5e737
14 changed files with 319 additions and 53 deletions
153
app/public/messages.js
Normal file
153
app/public/messages.js
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
const STATE = {
|
||||||
|
id: 0,
|
||||||
|
chat_id: "",
|
||||||
|
observer: null,
|
||||||
|
is_loading: false,
|
||||||
|
stream_element: null,
|
||||||
|
first_message_time: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
function create_streamer(chat_id, hook_element) {
|
||||||
|
STATE.chat_id = chat_id;
|
||||||
|
STATE.stream_element = hook_element.parentElement;
|
||||||
|
|
||||||
|
STATE.observer = new IntersectionObserver(
|
||||||
|
() => {
|
||||||
|
load_messages();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: STATE.stream_element,
|
||||||
|
rootMargin: "0px",
|
||||||
|
scrollMargin: "0px",
|
||||||
|
threshold: 1.0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
STATE.observer.observe(hook_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_messages() {
|
||||||
|
if (STATE.is_loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATE.is_loading = true;
|
||||||
|
STATE.id += 1;
|
||||||
|
|
||||||
|
fetch(
|
||||||
|
`/chats/_templates/chat/${STATE.chat_id}/messages/before/${STATE.first_message_time}?use_id=${STATE.id}`,
|
||||||
|
)
|
||||||
|
.then((res) => res.text())
|
||||||
|
.then((res) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
STATE.is_loading = false;
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
STATE.stream_element.innerHTML += res;
|
||||||
|
STATE.first_message_time = Number.parseInt(
|
||||||
|
document
|
||||||
|
.getElementById(`msgs_data_${STATE.id}`)
|
||||||
|
.getAttribute("data-first-message-time"),
|
||||||
|
);
|
||||||
|
|
||||||
|
// STATE.stream_element.scrollTo(0, STATE.stream_element.scrollHeight);
|
||||||
|
|
||||||
|
if (document.getElementById(`msgs_quit_${STATE.id}`)) {
|
||||||
|
STATE.observer.disconnect();
|
||||||
|
console.log("quit");
|
||||||
|
} else {
|
||||||
|
STATE.observer.unobserve(
|
||||||
|
STATE.stream_element.querySelector(
|
||||||
|
"[ui_ident=data_marker]",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const element = document.createElement("div");
|
||||||
|
element.setAttribute("ui_ident", "data_marker");
|
||||||
|
STATE.stream_element.append(element);
|
||||||
|
STATE.observer.observe(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_message(id) {
|
||||||
|
STATE.is_loading = true;
|
||||||
|
fetch(`/chats/_templates/message/${id}`)
|
||||||
|
.then((res) => res.text())
|
||||||
|
.then((res) => {
|
||||||
|
STATE.is_loading = false;
|
||||||
|
STATE.stream_element.innerHTML = `${res}${STATE.stream_element.innerHTML}`;
|
||||||
|
mark_message_read();
|
||||||
|
read_receipt();
|
||||||
|
STATE.stream_element.scrollTo(0, STATE.stream_element.scrollHeight);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sock_con() {
|
||||||
|
const socket = new WebSocket(
|
||||||
|
`//${window.location.origin.split("//")[1]}/api/v1/chats/${STATE.chat_id}/_connect`,
|
||||||
|
);
|
||||||
|
|
||||||
|
socket.addEventListener("message", async (event) => {
|
||||||
|
if (event.data === "Ping") {
|
||||||
|
return socket.send("Pong");
|
||||||
|
}
|
||||||
|
|
||||||
|
const msg = JSON.parse(event.data);
|
||||||
|
|
||||||
|
if (msg.method === "MessageCreate") {
|
||||||
|
render_message(msg.body);
|
||||||
|
} else if (msg.method === "MessageDelete") {
|
||||||
|
if (document.getElementById(`message_${msg.body}`)) {
|
||||||
|
document.getElementById(`message_${msg.body}`).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_message(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const body = new FormData();
|
||||||
|
|
||||||
|
body.append(
|
||||||
|
"body",
|
||||||
|
JSON.stringify({
|
||||||
|
content: e.target.content.value,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
fetch(`/api/v1/messages/${STATE.chat_id}`, { method: "POST", body })
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((res) => {
|
||||||
|
if (res.ok) {
|
||||||
|
e.target.reset();
|
||||||
|
} else {
|
||||||
|
show_message(res.message, res.ok);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function mark_message_read() {
|
||||||
|
fetch(`/api/v1/chats/${STATE.chat_id}/read_message`, {
|
||||||
|
method: "POST",
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((res) => {
|
||||||
|
if (!res.ok) {
|
||||||
|
show_message(res.message, res.ok);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_receipt() {
|
||||||
|
if (document.getElementById("delivered_read_status")) {
|
||||||
|
document.getElementById("delivered_read_status").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`/chats/_templates/chat/${STATE.chat_id}/read_receipt`)
|
||||||
|
.then((res) => res.text())
|
||||||
|
.then((res) => {
|
||||||
|
STATE.stream_element.innerHTML = `${res}${STATE.stream_element.innerHTML}`;
|
||||||
|
});
|
||||||
|
}
|
|
@ -746,3 +746,24 @@ menu.col {
|
||||||
width: 25rem;
|
width: 25rem;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* messages */
|
||||||
|
.message {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message:not(.mine) {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message .inner {
|
||||||
|
padding: var(--pad-2) var(--pad-3);
|
||||||
|
background: var(--color-surface);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.mine .inner {
|
||||||
|
background: var(--color-primary);
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
|
@ -19,30 +19,16 @@
|
||||||
("style" "flex: 1 0 auto")
|
("style" "flex: 1 0 auto")
|
||||||
(div
|
(div
|
||||||
("class" "card flex flex_rev_col gap_2")
|
("class" "card flex flex_rev_col gap_2")
|
||||||
("style" "flex: 1 0 auto")
|
("style" "flex: 1 0 auto; max-height: 80dvh; overflow: auto")
|
||||||
("id" "messages_stream")
|
("id" "messages_stream")
|
||||||
(text "{% if chat.last_message_created > 0 -%}")
|
|
||||||
(div
|
|
||||||
("class" "flex gap_ch items_center")
|
|
||||||
("id" "delivered_read_status")
|
|
||||||
(text "{% if chat.last_message_read_by|length <= 1 -%}")
|
|
||||||
; just delivered
|
|
||||||
(text "{{ icon \"check\" }}")
|
|
||||||
(text "{{ chat.last_message_created|int|date(format=\"%Y-%m-%d %H:%M\", timezone=\"Etc/UTC\") }} UTC }}")
|
|
||||||
(text "{%- else -%}")
|
|
||||||
; delivered and read by at least two people
|
|
||||||
(text "{{ icon \"check-check\" }}")
|
|
||||||
(text "{% for uid in chat.last_message_read_by -%}")
|
|
||||||
(text "{{ components::avatar(id=uid) }}")
|
|
||||||
(text "{%- endfor %}")
|
|
||||||
(text "{%- endif %}"))
|
|
||||||
(text "{%- endif %}")
|
|
||||||
|
|
||||||
(text "{% if messages|length == 0 -%}")
|
(text "{% if messages|length == 0 -%}")
|
||||||
(i ("class" "flex gap_ch items_center fade") (text "{{ icon \"star\" }} This is the start of the chat!"))
|
(i ("class" "flex gap_ch items_center fade") (text "{{ icon \"star\" }} This is the start of the chat!"))
|
||||||
(text "{%- endif %}"))
|
(text "{%- endif %}")
|
||||||
|
|
||||||
|
(div ("ui_ident" "data_marker")))
|
||||||
(form
|
(form
|
||||||
("class" "card flex flex_row items_center gap_2")
|
("class" "card flex flex_row items_center gap_2")
|
||||||
|
("onsubmit" "create_message(event)")
|
||||||
(input
|
(input
|
||||||
("type" "text")
|
("type" "text")
|
||||||
("class" "w_full")
|
("class" "w_full")
|
||||||
|
@ -53,6 +39,10 @@
|
||||||
("class" "button")
|
("class" "button")
|
||||||
(text "{{ icon \"send\" }}"))))
|
(text "{{ icon \"send\" }}"))))
|
||||||
|
|
||||||
|
(script ("src" "/public/messages.js"))
|
||||||
(script
|
(script
|
||||||
(text ""))
|
(text "create_streamer(\"{{ chat.id }}\", document.querySelector(\"[ui_ident=data_marker]\"));
|
||||||
|
sock_con();
|
||||||
|
mark_message_read();
|
||||||
|
read_receipt();"))
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
|
@ -22,18 +22,18 @@
|
||||||
; advanced
|
; advanced
|
||||||
(text "{% if chat.style == \"Direct\" -%} {% for member in members -%} {% if member.id != user.id -%}")
|
(text "{% if chat.style == \"Direct\" -%} {% for member in members -%} {% if member.id != user.id -%}")
|
||||||
; direct message; user that ISN'T the current user
|
; direct message; user that ISN'T the current user
|
||||||
(text "{{ components::avatar(id=member.id, size=avatar_size) }}")
|
(text "{{ self::avatar(id=member.id, size=avatar_size) }}")
|
||||||
(text "{{ components::username(user=member) }}")
|
(text "{{ self::username(user=member) }}")
|
||||||
(text "{%- endif %} {%- endfor %} {%- else -%}")
|
(text "{%- endif %} {%- endfor %} {%- else -%}")
|
||||||
; group chat
|
; group chat
|
||||||
(text "{% for member in members -%} {{ components::avatar(id=member.id, size=avatar_size) }} {%- endfor %}")
|
(text "{% for member in members -%} {{ self::avatar(id=member.id, size=avatar_size) }} {%- endfor %}")
|
||||||
(b (text "{{ chat.style.Group.name }}"))
|
(b (text "{{ chat.style.Group.name }}"))
|
||||||
(text "{%- endif %}")
|
(text "{%- endif %}")
|
||||||
(text "{%- else -%}")
|
(text "{%- else -%}")
|
||||||
; NOT advanced
|
; NOT advanced
|
||||||
(text "{% if chat.style == \"Direct\" -%} {% for member in members -%} {% if member.id != user.id -%}")
|
(text "{% if chat.style == \"Direct\" -%} {% for member in members -%} {% if member.id != user.id -%}")
|
||||||
; direct message; user that ISN'T the current user
|
; direct message; user that ISN'T the current user
|
||||||
(text "{{ user.username }}")
|
(text "{{ member.username }}")
|
||||||
(text "{%- endif %} {%- endfor %} {%- else -%}")
|
(text "{%- endif %} {%- endfor %} {%- else -%}")
|
||||||
; group chat
|
; group chat
|
||||||
(text "{{ chat.style.Group.name }}")
|
(text "{{ chat.style.Group.name }}")
|
||||||
|
@ -44,8 +44,9 @@
|
||||||
(text "{% macro message(message) -%}")
|
(text "{% macro message(message) -%}")
|
||||||
(div
|
(div
|
||||||
("class" "flex w_full gap_ch message {%- if user.id == message.owner %} justify_right mine {%- endif %}")
|
("class" "flex w_full gap_ch message {%- if user.id == message.owner %} justify_right mine {%- endif %}")
|
||||||
|
("id" "message_{{ message.id }}")
|
||||||
(div
|
(div
|
||||||
("class" "inner no_p_margin")
|
("class" "inner no_p_margin")
|
||||||
(text "{{ message.content|markdown|safe }}"))
|
(text "{{ message.content|markdown|safe }}"))
|
||||||
(text "{{ components::avatar(id=uid) }}"))
|
(text "{{ self::avatar(id=message.owner) }}"))
|
||||||
(text "{%- endmacro %}")
|
(text "{%- endmacro %}")
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
|
|
||||||
// redirect
|
// redirect
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = \"/app\";
|
window.location.href = \"/chats\";
|
||||||
}, 150);
|
}, 150);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
(text "{%- import \"components.lisp\" as components -%}")
|
(text "{%- import \"components.lisp\" as components -%}")
|
||||||
(text "{{ components::message(message) }}")
|
(text "{{ components::message(message=message) }}")
|
||||||
|
|
|
@ -1,4 +1,15 @@
|
||||||
(text "{%- import \"components.lisp\" as components -%}")
|
(text "{%- import \"components.lisp\" as components -%}")
|
||||||
(text "{% for message in messages -%}")
|
(text "{% for message in messages -%}")
|
||||||
(text "{{ components::message(message) }}")
|
(text "{{ components::message(message=message) }}")
|
||||||
(text "{%- endfor %}")
|
(text "{%- endfor %}")
|
||||||
|
|
||||||
|
(div
|
||||||
|
("class" "hidden")
|
||||||
|
("id" "msgs_data_{{ id }}")
|
||||||
|
("data-first-message-time" "{{ first_message_time }}"))
|
||||||
|
|
||||||
|
(text "{% if messages|length == 0 -%}")
|
||||||
|
(div
|
||||||
|
("class" "hidden")
|
||||||
|
("id" "msgs_quit_{{ id }}"))
|
||||||
|
(text "{%- endif %}")
|
||||||
|
|
17
app/templates_src/read_receipt.lisp
Normal file
17
app/templates_src/read_receipt.lisp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
(text "{%- import \"components.lisp\" as components -%}")
|
||||||
|
(text "{% if chat.last_message_created > 0 -%}")
|
||||||
|
(div
|
||||||
|
("class" "flex gap_ch items_center")
|
||||||
|
("id" "delivered_read_status")
|
||||||
|
(text "{% if chat.last_message_read_by|length <= 1 -%}")
|
||||||
|
; just delivered
|
||||||
|
(text "{{ icon \"check\" }}")
|
||||||
|
(text "{{ chat.last_message_created|int|date(format=\"%H:%M\", timezone=\"Etc/UTC\") }} UTC")
|
||||||
|
(text "{%- else -%}")
|
||||||
|
; delivered and read by at least two people
|
||||||
|
(text "{{ icon \"check-check\" }}")
|
||||||
|
(text "{% for uid in chat.last_message_read_by -%}")
|
||||||
|
(text "{{ components::avatar(id=uid) }}")
|
||||||
|
(text "{%- endfor %}")
|
||||||
|
(text "{%- endif %}"))
|
||||||
|
(text "{%- endif %}")
|
|
@ -58,7 +58,7 @@ impl DataManager {
|
||||||
|
|
||||||
let res = query_rows!(
|
let res = query_rows!(
|
||||||
&conn,
|
&conn,
|
||||||
"SELECT * FROM t_chats WHERE members LIKE $1 ORDER BY last_message_created LIMIT $2 OFFSET $3",
|
"SELECT * FROM t_chats WHERE members LIKE $1 ORDER BY last_message_created DESC LIMIT $2 OFFSET $3",
|
||||||
params![
|
params![
|
||||||
&format!("%{id}%"),
|
&format!("%{id}%"),
|
||||||
&(batch as i64),
|
&(batch as i64),
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl DataManager {
|
||||||
|
|
||||||
let res = query_rows!(
|
let res = query_rows!(
|
||||||
&conn,
|
&conn,
|
||||||
"SELECT * FROM t_messages WHERE chat = $1 LIMIT $2 OFFSET $3",
|
"SELECT * FROM t_messages WHERE chat = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
|
||||||
params![&(id as i64), &(batch as i64), &((page * batch) as i64)],
|
params![&(id as i64), &(batch as i64), &((page * batch) as i64)],
|
||||||
|x| { Self::get_message_from_row(x) }
|
|x| { Self::get_message_from_row(x) }
|
||||||
);
|
);
|
||||||
|
@ -68,7 +68,7 @@ impl DataManager {
|
||||||
|
|
||||||
let res = query_rows!(
|
let res = query_rows!(
|
||||||
&conn,
|
&conn,
|
||||||
"SELECT * FROM t_messages WHERE chat = $1 AND created < $2 LIMIT $3 OFFSET $4",
|
"SELECT * FROM t_messages WHERE chat = $1 AND created < $2 ORDER BY created DESC LIMIT $3 OFFSET $4",
|
||||||
params![
|
params![
|
||||||
&(id as i64),
|
&(id as i64),
|
||||||
&(before as i64),
|
&(before as i64),
|
||||||
|
@ -128,7 +128,7 @@ impl DataManager {
|
||||||
data.chat,
|
data.chat,
|
||||||
SocketMessage {
|
SocketMessage {
|
||||||
method: SocketMethod::MessageCreate,
|
method: SocketMethod::MessageCreate,
|
||||||
body: serde_json::to_string(&data).unwrap(),
|
body: data.id.to_string(),
|
||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -158,6 +158,42 @@ pub async fn update_info_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn read_message_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Path(id): Path<usize>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let data = &(data.read().await).0;
|
||||||
|
let user = match get_user_from_token!(jar, data.2) {
|
||||||
|
Some(x) => x,
|
||||||
|
None => return Json(Error::NotAllowed.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut chat = match data.get_chat_by_id(id).await {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
return Json(e.into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !chat.last_message_read_by.contains(&user.id) {
|
||||||
|
// update chat
|
||||||
|
chat.last_message_read_by.push(user.id);
|
||||||
|
if let Err(e) = data
|
||||||
|
.update_chat_last_message_read_by(id, chat.last_message_read_by)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return Json(e.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "Success".to_string(),
|
||||||
|
payload: (),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle a subscription to the websocket.
|
/// Handle a subscription to the websocket.
|
||||||
pub async fn subscription_handler(
|
pub async fn subscription_handler(
|
||||||
jar: CookieJar,
|
jar: CookieJar,
|
||||||
|
|
|
@ -19,9 +19,13 @@ pub fn routes() -> Router {
|
||||||
.route("/chats", post(chats::create_request))
|
.route("/chats", post(chats::create_request))
|
||||||
.route("/chats/{id}/leave", post(chats::leave_request))
|
.route("/chats/{id}/leave", post(chats::leave_request))
|
||||||
.route("/chats/{id}/info", post(chats::update_info_request))
|
.route("/chats/{id}/info", post(chats::update_info_request))
|
||||||
.route("/chats/{id}/_connect", post(chats::subscription_handler))
|
.route("/chats/{id}/_connect", get(chats::subscription_handler))
|
||||||
|
.route(
|
||||||
|
"/chats/{id}/read_message",
|
||||||
|
post(chats::read_message_request),
|
||||||
|
)
|
||||||
// messages
|
// messages
|
||||||
.route("/messages", post(messages::create_request))
|
.route("/messages/{id}", post(messages::create_request))
|
||||||
.route("/messages/{id}", delete(messages::delete_request))
|
.route("/messages/{id}", delete(messages::delete_request))
|
||||||
.route("/messages/{id}", put(messages::update_content_request))
|
.route("/messages/{id}", put(messages::update_content_request))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
|
use serde::Deserialize;
|
||||||
use tetratto_core::model::Error;
|
use tetratto_core::model::Error;
|
||||||
|
|
||||||
pub async fn list_request(
|
pub async fn list_request(
|
||||||
|
@ -106,33 +107,21 @@ pub async fn single_message_request(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut chat = match data.get_chat_by_id(message.chat).await {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(e) => {
|
|
||||||
return Err(render_error(e, tera, data.0.0.clone(), Some(user)).await);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !chat.last_message_read_by.contains(&user.id) {
|
|
||||||
// update chat
|
|
||||||
chat.last_message_read_by.push(user.id);
|
|
||||||
if let Err(e) = data
|
|
||||||
.update_chat_last_message_read_by(user.id, chat.last_message_read_by)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
return Err(render_error(e, tera, data.0.0.clone(), Some(user)).await);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut ctx = default_context(&data.0.0, &build_code, &Some(user));
|
let mut ctx = default_context(&data.0.0, &build_code, &Some(user));
|
||||||
ctx.insert("message", &message);
|
ctx.insert("message", &message);
|
||||||
Ok(Html(tera.render("message.lisp", &ctx).unwrap()))
|
Ok(Html(tera.render("message.lisp", &ctx).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct MessagesProps {
|
||||||
|
pub use_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn messages_request(
|
pub async fn messages_request(
|
||||||
jar: CookieJar,
|
jar: CookieJar,
|
||||||
Extension(data): Extension<State>,
|
Extension(data): Extension<State>,
|
||||||
Path((id, before)): Path<(usize, usize)>,
|
Path((id, before)): Path<(usize, usize)>,
|
||||||
|
Query(props): Query<MessagesProps>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let (ref data, ref tera, ref build_code) = *data.read().await;
|
let (ref data, ref tera, ref build_code) = *data.read().await;
|
||||||
let user = match get_user_from_token!(jar, data.2) {
|
let user = match get_user_from_token!(jar, data.2) {
|
||||||
|
@ -142,7 +131,11 @@ pub async fn messages_request(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let messages = match data.get_messages_by_chat_before(id, before, 12, 0).await {
|
let messages = match if before > 0 {
|
||||||
|
data.get_messages_by_chat_before(id, before, 12, 0).await
|
||||||
|
} else {
|
||||||
|
data.get_messages_by_chat(id, 12, 0).await
|
||||||
|
} {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(render_error(e, tera, data.0.0.clone(), Some(user)).await);
|
return Err(render_error(e, tera, data.0.0.clone(), Some(user)).await);
|
||||||
|
@ -150,6 +143,42 @@ pub async fn messages_request(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ctx = default_context(&data.0.0, &build_code, &Some(user));
|
let mut ctx = default_context(&data.0.0, &build_code, &Some(user));
|
||||||
|
|
||||||
|
ctx.insert(
|
||||||
|
"first_message_time",
|
||||||
|
&match messages.first() {
|
||||||
|
Some(x) => x.created,
|
||||||
|
None => 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
ctx.insert("messages", &messages);
|
ctx.insert("messages", &messages);
|
||||||
|
ctx.insert("id", &props.use_id);
|
||||||
|
|
||||||
Ok(Html(tera.render("messages.lisp", &ctx).unwrap()))
|
Ok(Html(tera.render("messages.lisp", &ctx).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn read_receipt_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Path(id): Path<usize>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let (ref data, ref tera, ref build_code) = *data.read().await;
|
||||||
|
let user = match get_user_from_token!(jar, data.2) {
|
||||||
|
Some(x) => x,
|
||||||
|
None => {
|
||||||
|
return Err(render_error(Error::NotAllowed, tera, data.0.0.clone(), None).await);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let chat = match data.get_chat_by_id(id).await {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(render_error(e, tera, data.0.0.clone(), Some(user)).await);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ctx = default_context(&data.0.0, &build_code, &Some(user));
|
||||||
|
ctx.insert("chat", &chat);
|
||||||
|
Ok(Html(tera.render("read_receipt.lisp", &ctx).unwrap()))
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,10 @@ pub fn routes() -> Router {
|
||||||
"/chats/_templates/chat/{id}/messages/before/{before}",
|
"/chats/_templates/chat/{id}/messages/before/{before}",
|
||||||
get(chats::messages_request),
|
get(chats::messages_request),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/chats/_templates/chat/{id}/read_receipt",
|
||||||
|
get(chats::read_receipt_request),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue