[wip] notifications

This commit is contained in:
GitHub
2023-02-07 11:39:03 +08:00
parent 9f2b138973
commit 2a24555562
5 changed files with 118 additions and 84 deletions

View File

@@ -15,7 +15,7 @@ use super::{
extract_element, get_batch, get_count_by_prefix, get_ids_by_prefix, get_ids_by_tag,
get_inn_role, get_one, get_range, get_site_config, get_uid_by_name, has_unread, incr_id,
into_response, is_mod, ivec_to_u32,
notification::{mark_read, NtType},
notification::{add_notification, mark_read, NtType},
timestamp_to_date, u32_to_ivec, u8_slice_to_u32, user_stats,
utils::md2html,
Claim, Comment, FormPost, Inn, PageData, ParamsPage, Post, User, ValidatedForm,
@@ -33,7 +33,7 @@ use axum::{
use bincode::config::standard;
use chrono::{DateTime, NaiveDateTime, Utc};
use serde::Deserialize;
use sled::{Batch, Db, IVec};
use sled::{Batch, Db};
use std::{collections::BTreeSet, path::PathBuf};
use validator::Validate;
@@ -1342,7 +1342,6 @@ pub(crate) async fn comment_post(
// extract @username or @uid notificaiton
let notifications = extract_element(&content, 5, '@');
let notification_tree = db.open_tree("notifications")?;
for notification in &notifications {
let (uid, username) = match notification.parse::<u32>() {
Ok(uid) => {
@@ -1366,18 +1365,9 @@ pub(crate) async fn comment_post(
content = content.replace(&from, &to);
// notify user to be mentioned in comment
// prevent duplicate notifications
if uid != post.uid {
let nid = incr_id(&db, "notifications_count")?;
let k = [
&u32_to_ivec(uid),
&u32_to_ivec(nid),
&IVec::from(&[NtType::PostMention as u8]),
]
.concat();
let v = [&pid_ivec, &u32_to_ivec(cid), &IVec::from(&[0])].concat();
notification_tree.insert(k, v)?;
add_notification(&db, uid, NtType::PostMention, pid, cid)?;
}
}
@@ -1438,15 +1428,7 @@ pub(crate) async fn comment_post(
// notify post author
if post.uid != claim.uid {
let nid = incr_id(&db, "notifications_count")?;
let k = [
&u32_to_ivec(post.uid),
&u32_to_ivec(nid),
&IVec::from(&[NtType::PostComment as u8]),
]
.concat();
let v = [&pid_ivec, &u32_to_ivec(cid), &IVec::from(&[0])].concat();
notification_tree.insert(k, v)?;
add_notification(&db, post.uid, NtType::PostComment, pid, cid)?;
}
user_stats(&db, claim.uid, "comment")?;

View File

@@ -9,13 +9,13 @@ use axum::{
};
use bincode::config::standard;
use serde::Deserialize;
use sled::Db;
use sled::{Db, IVec};
use crate::error::AppError;
use super::{
get_ids_by_prefix, get_one, get_site_config, has_unread, into_response, u32_to_ivec,
u8_slice_to_u32, Claim, Comment, PageData, Post, Solo, User,
get_ids_by_prefix, get_one, get_site_config, has_unread, incr_id, into_response, u32_to_ivec,
u8_slice_to_u32, Claim, Comment, Inn, PageData, Post, Solo, User,
};
/// notification.html
@@ -217,7 +217,43 @@ pub(crate) async fn notification(
};
notifications.push(notification);
}
_ => todo!(),
NtType::InnNotification => {
let role = u8_slice_to_u32(&value[0..4]);
let iid = u8_slice_to_u32(&value[4..8]);
let inn: Inn = get_one(&db, "inns", iid)?;
let notification = Notification {
nid,
nt_type: nt_type.to_string(),
uid: claim.uid,
username: claim.username.clone(),
id1: 0,
id2: 0,
id3: 0,
content1: "".into(),
content2: format!(
"Your role in {} (id:{}) has been changed to {role}",
inn.inn_name, iid
),
is_read: value[8] == 1,
};
notifications.push(notification);
}
NtType::SiteNotification => {
let role = u8_slice_to_u32(&value[0..4]);
let notification = Notification {
nid,
nt_type: nt_type.to_string(),
uid: claim.uid,
username: claim.username.clone(),
id1: 0,
id2: 0,
id3: 0,
content1: "".into(),
content2: format!("Your site role has been changed to {role}"),
is_read: value[8] == 1,
};
notifications.push(notification);
}
}
if n >= 30 {
@@ -258,3 +294,23 @@ struct InnNotification {
iid: u32,
uid: u32,
}
pub(super) fn add_notification(
db: &Db,
uid: u32,
nt_type: NtType,
id1: u32,
id2: u32,
) -> Result<(), AppError> {
let nid = incr_id(db, "notifications_count")?;
let k = [
&u32_to_ivec(uid),
&u32_to_ivec(nid),
&IVec::from(&[nt_type as u8]),
]
.concat();
let v = [&u32_to_ivec(id1), &u32_to_ivec(id2), &IVec::from(&[0])].concat();
db.open_tree("notifications")?.insert(k, v)?;
Ok(())
}

View File

@@ -1,7 +1,7 @@
use super::{
extract_element, get_count_by_prefix, get_ids_by_prefix, get_ids_by_tag, get_one, get_range,
get_referer, get_site_config, get_uid_by_name, has_unread, incr_id, into_response, ivec_to_u32,
notification::{mark_read, NtType},
notification::{add_notification, mark_read, NtType},
timestamp_to_date, u32_to_ivec, u8_slice_to_u32, user_stats,
utils::md2html,
Claim, IterType, PageData, ParamsPage, Solo, User, ValidatedForm,
@@ -16,7 +16,7 @@ use axum::{
use bincode::config::standard;
use chrono::Utc;
use serde::Deserialize;
use sled::{Db, IVec};
use sled::Db;
use validator::Validate;
/// Form data: `/solo/user/:uid` solo create.
@@ -370,9 +370,10 @@ pub(crate) async fn solo_post(
let mut hashtags = Vec::new();
let replied_uesr;
let reply_to = if input.reply_to == 0 {
let reply_to;
if input.reply_to == 0 {
replied_uesr = None;
None
reply_to = None;
} else {
let mut solo_replied: Solo = get_one(&db, "solos", input.reply_to)?;
solo_replied.replies.push(sid);
@@ -382,23 +383,16 @@ pub(crate) async fn solo_post(
.insert(&u32_to_ivec(input.reply_to), solo_replied_encode)?;
if solo_replied.uid != uid {
let nid = incr_id(&db, "notifications_count")?;
let k = [
&u32_to_ivec(solo_replied.uid),
&u32_to_ivec(nid),
&IVec::from(&[NtType::SoloComment as u8]),
]
.concat();
let v = [
&u32_to_ivec(input.reply_to),
&u32_to_ivec(sid),
&IVec::from(&[0]),
]
.concat();
db.open_tree("notifications")?.insert(k, v)?;
add_notification(
&db,
solo_replied.uid,
NtType::SoloComment,
input.reply_to,
sid,
)?;
}
Some(input.reply_to)
reply_to = Some(input.reply_to)
};
if visibility == 0 {
@@ -417,7 +411,6 @@ pub(crate) async fn solo_post(
// extract @username or @uid notificaiton
let notifications = extract_element(&content, 5, '@');
let notification_tree = db.open_tree("notifications")?;
for notification in &notifications {
let (uid, username) = match notification.parse::<u32>() {
Ok(uid) => {
@@ -442,15 +435,7 @@ pub(crate) async fn solo_post(
// notify user to be mentioned in comment
if uid != claim.uid && replied_uesr != Some(uid) {
let nid = incr_id(&db, "notifications_count")?;
let k = [
&u32_to_ivec(uid),
&u32_to_ivec(nid),
&IVec::from(&[NtType::SoloMention as u8]),
]
.concat();
let v = [&sid_ivec, &u32_to_ivec(0), &IVec::from(&[0])].concat();
notification_tree.insert(k, v)?;
add_notification(&db, uid, NtType::SoloMention, sid, 0)?;
}
}
}

View File

@@ -2,9 +2,10 @@
use super::{
generate_nanoid_expire, get_count_by_prefix, get_ids_by_prefix, get_inn_role, get_one,
get_range, get_site_config, get_uid_by_name, incr_id, into_response, is_mod, timestamp_to_date,
u32_to_ivec, u8_slice_to_u32, user_stats, Claim, Inn, IterType, PageData, ParamsPage,
SiteConfig, User, ValidatedForm,
get_range, get_site_config, get_uid_by_name, incr_id, into_response, is_mod,
notification::{add_notification, NtType},
timestamp_to_date, u32_to_ivec, u8_slice_to_u32, user_stats, Claim, Inn, IterType, PageData,
ParamsPage, SiteConfig, User, ValidatedForm,
};
use crate::{config::CONFIG, controller::get_count, error::AppError};
use ::rand::{thread_rng, Rng};
@@ -360,15 +361,15 @@ pub(crate) async fn role_post(
let inn_users_k = [&u32_to_ivec(id), &u32_to_ivec(uid)].concat();
// protect super
if let Some(user_inn_role) = get_inn_role(&db, id, uid)? {
if user_inn_role > inn_role {
return Err(AppError::Unauthorized);
}
let old_inn_role = get_inn_role(&db, id, uid)?.unwrap_or_default();
if user_inn_role == 1 && form.role != "Pending" {
db.open_tree("inn_apply")?.remove(&inn_users_k)?;
}
// protect super
if old_inn_role > inn_role {
return Err(AppError::Unauthorized);
}
if old_inn_role == 1 && form.role != "Pending" {
db.open_tree("inn_apply")?.remove(&inn_users_k)?;
}
let inn_role: u8 = match form.role.as_str() {
@@ -391,20 +392,24 @@ pub(crate) async fn role_post(
_ => unreachable!(),
};
db.open_tree("inn_users")?
.insert(&inn_users_k, &[inn_role])?;
if old_inn_role != inn_role {
db.open_tree("inn_users")?
.insert(&inn_users_k, &[inn_role])?;
let user_inns_k = [&u32_to_ivec(uid), &u32_to_ivec(id)].concat();
if inn_role >= 3 {
db.open_tree("user_inns")?.insert(&user_inns_k, &[])?;
} else {
db.open_tree("user_inns")?.remove(&user_inns_k)?;
}
let user_inns_k = [&u32_to_ivec(uid), &u32_to_ivec(id)].concat();
if inn_role >= 3 {
db.open_tree("user_inns")?.insert(&user_inns_k, &[])?;
} else {
db.open_tree("user_inns")?.remove(&user_inns_k)?;
}
if inn_role >= 8 {
db.open_tree("mod_inns")?.insert(&user_inns_k, &[])?;
} else {
db.open_tree("mod_inns")?.remove(&user_inns_k)?;
if inn_role >= 8 {
db.open_tree("mod_inns")?.insert(&user_inns_k, &[])?;
} else {
db.open_tree("mod_inns")?.remove(&user_inns_k)?;
}
add_notification(&db, uid, NtType::InnNotification, inn_role as u32, id)?;
}
target = format!("/user/list?filter=inn&id={id}");
@@ -415,18 +420,24 @@ pub(crate) async fn role_post(
}
let mut user: User = get_one(&db, "users", uid)?;
user.role = match form.role.as_str() {
let role = match form.role.as_str() {
"Admin" => 255,
"Senior" => 100,
"Standard" => 10,
"Banned" => 0,
_ => unreachable!(),
};
let user_encode = bincode::encode_to_vec(&user, standard())?;
db.open_tree("users")?
.insert(&u32_to_ivec(uid), user_encode)?;
Claim::update_role(&db, uid)?;
if user.role != role {
user.role = role;
let user_encode = bincode::encode_to_vec(&user, standard())?;
db.open_tree("users")?
.insert(&u32_to_ivec(uid), user_encode)?;
Claim::update_role(&db, uid)?;
add_notification(&db, uid, NtType::SiteNotification, role as u32, 0)?;
}
target = "/user/list".to_string();
}
Ordering::Less => unreachable!(),

View File

@@ -89,7 +89,7 @@
{% if !nt.is_read %}
<a href="/notification?nid={{nt.nid}}&op_type=mark"><span class="tag is-info" title="Mark as read">✔️</span></a>
{% endif %}
<a href="/notification?iid={{nt.nid}}&op_type=delete"><span class="tag is-danger" title="Delete notification"></span></a>
<a href="/notification?nid={{nt.nid}}&op_type=delete"><span class="tag is-danger" title="Delete notification"></span></a>
</div>
</div>
{% endfor %}