generated from t/malachite
add: message notifications
This commit is contained in:
parent
ca1eca967c
commit
361d3d8e30
9 changed files with 100 additions and 13 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -2998,7 +2998,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||
|
||||
[[package]]
|
||||
name = "tawny"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"axum",
|
||||
|
@ -3015,7 +3015,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"tera",
|
||||
"tetratto-core 16.0.2",
|
||||
"tetratto-core 16.0.3",
|
||||
"tetratto-shared",
|
||||
"tokio",
|
||||
"toml 0.9.5",
|
||||
|
@ -3098,9 +3098,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tetratto-core"
|
||||
version = "16.0.2"
|
||||
version = "16.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380eed8dec18b0dcda3440d47375a1bacf94e42fdcd93d464e27682d005bf356"
|
||||
checksum = "9e3e81378d7f02a6f7d18bf9ca58e3885c6cb8611ca4d0536c76b320e6e4017a"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"base16ct",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "tawny"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
edition = "2024"
|
||||
authors = ["trisuaso"]
|
||||
repository = "https://trisua.com/t/tawny"
|
||||
|
@ -8,7 +8,7 @@ license = "AGPL-3.0-or-later"
|
|||
homepage = "https://tawny.cc"
|
||||
|
||||
[dependencies]
|
||||
tetratto-core = "16.0.2"
|
||||
tetratto-core = "16.0.3"
|
||||
tetratto-shared = "12.0.6"
|
||||
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
||||
pathbufd = "0.1.4"
|
||||
|
|
|
@ -12,6 +12,7 @@ const STATE = {
|
|||
function create_streamer(chat_id, hook_element) {
|
||||
STATE.chat_id = chat_id;
|
||||
STATE.stream_element = hook_element.parentElement;
|
||||
clear_notifications();
|
||||
|
||||
STATE.observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
|
@ -112,6 +113,10 @@ function sock_con() {
|
|||
|
||||
if (msg.method === "MessageCreate") {
|
||||
render_message(msg.body);
|
||||
|
||||
setTimeout(() => {
|
||||
clear_notifications();
|
||||
}, 150);
|
||||
} else if (msg.method === "MessageDelete") {
|
||||
if (document.getElementById(`message_${msg.body}`)) {
|
||||
document.getElementById(`message_${msg.body}`).remove();
|
||||
|
@ -420,3 +425,15 @@ function clear_replying_to() {
|
|||
STATE.replying_to = undefined;
|
||||
document.getElementById("replying_to_zone").classList.add("hidden");
|
||||
}
|
||||
|
||||
function clear_notifications() {
|
||||
fetch(`/api/v1/chats/${STATE.chat_id}/notifications`, {
|
||||
method: "DELETE",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
if (!res.ok) {
|
||||
show_message(res.message, res.ok);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -837,3 +837,22 @@ menu.col {
|
|||
.message .body p:last-of-type {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.message_reply_wrapper .message {
|
||||
opacity: 75%;
|
||||
padding: 0 4px;
|
||||
|
||||
& .body {
|
||||
min-height: unset;
|
||||
height: 26px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
& p {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
& .avatar {
|
||||
--size: 18px !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
|
||||
(text "{% if replying_to -%}")
|
||||
(div
|
||||
("style" "transform: scale(0.8); opacity: 75%; width: 110%")
|
||||
("class" "message_reply_wrapper")
|
||||
(text "{{ self::message(message=replying_to, hide_actions=true) }}"))
|
||||
(text "{%- endif %}")
|
||||
(text "{%- endmacro %}")
|
||||
|
|
|
@ -58,7 +58,9 @@
|
|||
("class" "card_nest w_full")
|
||||
("style" "max-width: 25rem")
|
||||
(div
|
||||
("class" "card banner"))
|
||||
("class" "card banner")
|
||||
(img
|
||||
("src" "{{ config.service_hosts.buckets }}/banners/{{ profile.id }}")))
|
||||
(div
|
||||
("class" "card flex flex_col gap_ch")
|
||||
(text "{{ components::avatar(id=profile.id, size=\"160px\") }}")
|
||||
|
@ -134,12 +136,17 @@
|
|||
}
|
||||
|
||||
.profile .banner {
|
||||
background-image: url(\"{{ config.service_hosts.buckets }}/banners/{{ profile.id }}\") !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-position: center !important;
|
||||
background-size: cover !important;
|
||||
border-radius: var(--radius) var(--radius) 0 0;
|
||||
height: 225px;
|
||||
overflow: hidden;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.profile .banner img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.card_nest .card:nth-child(2) {
|
||||
|
|
|
@ -540,3 +540,29 @@ pub async fn remove_pin_request(
|
|||
Err(e) => Json(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear_chat_notifications(
|
||||
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()),
|
||||
};
|
||||
|
||||
if let Err(e) = data
|
||||
.2
|
||||
.delete_all_notifications_by_tag(&user, &id.to_string())
|
||||
.await
|
||||
{
|
||||
return Json(e.into());
|
||||
}
|
||||
|
||||
Json(ApiReturn {
|
||||
ok: true,
|
||||
message: "Success".to_string(),
|
||||
payload: (),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use axum_extra::extract::CookieJar;
|
|||
use axum_image::{encode::save_webp_buffer, extract::JsonMultipart};
|
||||
use buckets_core::model::{MediaType, MediaUpload};
|
||||
use serde::Deserialize;
|
||||
use tetratto_core::model::{ApiReturn, Error, permissions::FinePermission};
|
||||
use tetratto_core::model::{ApiReturn, Error, auth::Notification, permissions::FinePermission};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateMessage {
|
||||
|
@ -121,6 +121,20 @@ pub async fn create_request(
|
|||
if let Err(e) = data.2.incr_user_missed_messages(member).await {
|
||||
return Json(e.into());
|
||||
}
|
||||
|
||||
let mut notif = Notification::new(
|
||||
"You've received a new message".to_string(),
|
||||
format!(
|
||||
"[@{}](/api/v1/auth/user/find/{}) has sent you a message in a [chat]({}/chats/{})",
|
||||
user.username, user.id, data.0.0.host, chat.id
|
||||
),
|
||||
member,
|
||||
);
|
||||
|
||||
notif.tag = chat.id.to_string();
|
||||
if let Err(e) = data.2.create_notification(notif).await {
|
||||
return Json(e.into());
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
|
|
|
@ -38,6 +38,10 @@ pub fn routes() -> Router {
|
|||
"/chats/{id}/pins/{message}",
|
||||
delete(chats::remove_pin_request),
|
||||
)
|
||||
.route(
|
||||
"/chats/{id}/notifications",
|
||||
delete(chats::clear_chat_notifications),
|
||||
)
|
||||
// messages
|
||||
.route("/messages/{id}", post(messages::create_request))
|
||||
.route("/messages/{id}", delete(messages::delete_request))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue