add: request-to-join communities
add: private joined communities setting add: "void" community add: ability to delete communities
This commit is contained in:
parent
3a8af17154
commit
d0c1fbcf9a
20 changed files with 669 additions and 122 deletions
|
@ -14,8 +14,9 @@ use tetratto_core::model::{
|
|||
use crate::{
|
||||
State, get_user_from_token,
|
||||
routes::api::v1::{
|
||||
CreateCommunity, UpdateCommunityContext, UpdateCommunityReadAccess, UpdateCommunityTitle,
|
||||
UpdateCommunityWriteAccess, UpdateMembershipRole,
|
||||
CreateCommunity, UpdateCommunityContext, UpdateCommunityJoinAccess,
|
||||
UpdateCommunityReadAccess, UpdateCommunityTitle, UpdateCommunityWriteAccess,
|
||||
UpdateMembershipRole,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -175,6 +176,31 @@ pub async fn update_write_access_request(
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn update_join_access_request(
|
||||
jar: CookieJar,
|
||||
Extension(data): Extension<State>,
|
||||
Path(id): Path<usize>,
|
||||
Json(req): Json<UpdateCommunityJoinAccess>,
|
||||
) -> impl IntoResponse {
|
||||
let data = &(data.read().await).0;
|
||||
let user = match get_user_from_token!(jar, data) {
|
||||
Some(ua) => ua,
|
||||
None => return Json(Error::NotAllowed.into()),
|
||||
};
|
||||
|
||||
match data
|
||||
.update_community_join_access(id, user, req.access)
|
||||
.await
|
||||
{
|
||||
Ok(_) => Json(ApiReturn {
|
||||
ok: true,
|
||||
message: "Community updated".to_string(),
|
||||
payload: (),
|
||||
}),
|
||||
Err(e) => Json(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_membership(
|
||||
jar: CookieJar,
|
||||
Extension(data): Extension<State>,
|
||||
|
@ -225,9 +251,9 @@ pub async fn create_membership(
|
|||
))
|
||||
.await
|
||||
{
|
||||
Ok(_) => Json(ApiReturn {
|
||||
Ok(m) => Json(ApiReturn {
|
||||
ok: true,
|
||||
message: "Community joined".to_string(),
|
||||
message: m,
|
||||
payload: (),
|
||||
}),
|
||||
Err(e) => Json(e.into()),
|
||||
|
@ -329,6 +355,31 @@ pub async fn update_membership_role(
|
|||
return Json(e.into());
|
||||
};
|
||||
|
||||
if let Err(e) = data.incr_community_member_count(community.id).await {
|
||||
return Json(e.into());
|
||||
}
|
||||
} else if req.role.check(CommunityPermission::REQUESTED) {
|
||||
// user was demoted to a request again
|
||||
if let Err(e) = data.decr_community_member_count(community.id).await {
|
||||
return Json(e.into());
|
||||
}
|
||||
} else if membership.role.check(CommunityPermission::REQUESTED) {
|
||||
// user was accepted to community
|
||||
if let Err(e) = data
|
||||
.create_notification(Notification::new(
|
||||
"You have been accepted into a community you requested to join!"
|
||||
.to_string(),
|
||||
format!(
|
||||
"You have been accepted into [{}](/community/{}).",
|
||||
community.title, community.title
|
||||
),
|
||||
membership.owner,
|
||||
))
|
||||
.await
|
||||
{
|
||||
return Json(e.into());
|
||||
};
|
||||
|
||||
if let Err(e) = data.incr_community_member_count(community.id).await {
|
||||
return Json(e.into());
|
||||
}
|
||||
|
|
|
@ -10,7 +10,10 @@ use axum::{
|
|||
};
|
||||
use serde::Deserialize;
|
||||
use tetratto_core::model::{
|
||||
communities::{CommunityContext, CommunityReadAccess, CommunityWriteAccess, PostContext},
|
||||
communities::{
|
||||
CommunityContext, CommunityJoinAccess, CommunityReadAccess, CommunityWriteAccess,
|
||||
PostContext,
|
||||
},
|
||||
communities_permissions::CommunityPermission,
|
||||
reactions::AssetType,
|
||||
};
|
||||
|
@ -53,6 +56,10 @@ pub fn routes() -> Router {
|
|||
"/communities/{id}/access/write",
|
||||
post(communities::communities::update_write_access_request),
|
||||
)
|
||||
.route(
|
||||
"/communities/{id}/access/join",
|
||||
post(communities::communities::update_join_access_request),
|
||||
)
|
||||
.route(
|
||||
"/communities/{id}/upload/avatar",
|
||||
post(communities::images::upload_avatar_request),
|
||||
|
@ -194,6 +201,11 @@ pub struct UpdateCommunityWriteAccess {
|
|||
pub access: CommunityWriteAccess,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct UpdateCommunityJoinAccess {
|
||||
pub access: CommunityJoinAccess,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreatePost {
|
||||
pub content: String,
|
||||
|
|
|
@ -11,26 +11,12 @@ use tetratto_core::model::{
|
|||
Error,
|
||||
auth::User,
|
||||
communities::{Community, CommunityReadAccess},
|
||||
communities_permissions::CommunityPermission,
|
||||
};
|
||||
|
||||
macro_rules! check_permissions {
|
||||
($community:ident, $jar:ident, $data:ident, $user:ident) => {
|
||||
match $community.read_access {
|
||||
CommunityReadAccess::Private => {
|
||||
if let Some(ref ua) = $user {
|
||||
if ua.id != $community.owner {
|
||||
return Err(Html(
|
||||
render_error(Error::NotAllowed, &$jar, &$data, &$user).await,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Html(
|
||||
render_error(Error::NotAllowed, &$jar, &$data, &$user).await,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
($community:ident, $jar:ident, $data:ident, $user:ident) => {{
|
||||
let mut is_member: bool = false;
|
||||
|
||||
if let Some(ref ua) = $user {
|
||||
if let Ok(membership) = $data
|
||||
|
@ -42,30 +28,54 @@ macro_rules! check_permissions {
|
|||
return Err(Html(
|
||||
render_error(Error::NotAllowed, &$jar, &$data, &$user).await,
|
||||
));
|
||||
} else if membership.role.check_member() {
|
||||
is_member = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match $community.read_access {
|
||||
CommunityReadAccess::Joined => {
|
||||
if !is_member {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! community_context_bools {
|
||||
($data:ident, $user:ident, $community:ident) => {{
|
||||
let membership = if let Some(ref ua) = $user {
|
||||
match $data
|
||||
.0
|
||||
.get_membership_by_owner_community(ua.id, $community.id)
|
||||
.await
|
||||
{
|
||||
Ok(m) => Some(m),
|
||||
Err(_) => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let is_owner = if let Some(ref ua) = $user {
|
||||
ua.id == $community.owner
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let is_joined = if let Some(ref ua) = $user {
|
||||
if let Ok(membership) = $data
|
||||
.0
|
||||
.get_membership_by_owner_community(ua.id, $community.id)
|
||||
.await
|
||||
{
|
||||
membership.role.check_member()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
let is_joined = if let Some(ref membership) = membership {
|
||||
membership.role.check_member()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let is_pending = if let Some(ref membership) = membership {
|
||||
membership.role.check(CommunityPermission::REQUESTED)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
@ -76,7 +86,7 @@ macro_rules! community_context_bools {
|
|||
false
|
||||
};
|
||||
|
||||
(is_owner, is_joined, can_post)
|
||||
(is_owner, is_joined, is_pending, can_post)
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -120,12 +130,16 @@ pub fn community_context(
|
|||
community: &Community,
|
||||
is_owner: bool,
|
||||
is_joined: bool,
|
||||
is_pending: bool,
|
||||
can_post: bool,
|
||||
can_read: bool,
|
||||
) {
|
||||
context.insert("community", &community);
|
||||
context.insert("is_owner", &is_owner);
|
||||
context.insert("is_joined", &is_joined);
|
||||
context.insert("is_pending", &is_pending);
|
||||
context.insert("can_post", &can_post);
|
||||
context.insert("can_read", &can_read);
|
||||
}
|
||||
|
||||
/// `/community/{title}`
|
||||
|
@ -143,8 +157,21 @@ pub async fn feed_request(
|
|||
Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
|
||||
};
|
||||
|
||||
if community.id == 0 {
|
||||
// don't show page for void community
|
||||
return Err(Html(
|
||||
render_error(
|
||||
Error::GeneralNotFound("community".to_string()),
|
||||
&jar,
|
||||
&data,
|
||||
&user,
|
||||
)
|
||||
.await,
|
||||
));
|
||||
}
|
||||
|
||||
// check permissions
|
||||
check_permissions!(community, jar, data, user);
|
||||
let can_read = check_permissions!(community, jar, data, user);
|
||||
|
||||
// ...
|
||||
let feed = match data
|
||||
|
@ -163,10 +190,19 @@ pub async fn feed_request(
|
|||
let lang = get_lang!(jar, data.0);
|
||||
let mut context = initial_context(&data.0.0, lang, &user).await;
|
||||
|
||||
let (is_owner, is_joined, can_post) = community_context_bools!(data, user, community);
|
||||
let (is_owner, is_joined, is_pending, can_post) =
|
||||
community_context_bools!(data, user, community);
|
||||
|
||||
context.insert("feed", &feed);
|
||||
community_context(&mut context, &community, is_owner, is_joined, can_post);
|
||||
community_context(
|
||||
&mut context,
|
||||
&community,
|
||||
is_owner,
|
||||
is_joined,
|
||||
is_pending,
|
||||
can_post,
|
||||
can_read,
|
||||
);
|
||||
|
||||
// return
|
||||
Ok(Html(
|
||||
|
@ -242,7 +278,7 @@ pub async fn post_request(
|
|||
};
|
||||
|
||||
// check permissions
|
||||
check_permissions!(community, jar, data, user);
|
||||
let can_read = check_permissions!(community, jar, data, user);
|
||||
|
||||
// ...
|
||||
let feed = match data.0.get_post_comments(post.id, 12, props.page).await {
|
||||
|
@ -257,7 +293,8 @@ pub async fn post_request(
|
|||
let lang = get_lang!(jar, data.0);
|
||||
let mut context = initial_context(&data.0.0, lang, &user).await;
|
||||
|
||||
let (is_owner, is_joined, can_post) = community_context_bools!(data, user, community);
|
||||
let (is_owner, is_joined, is_pending, can_post) =
|
||||
community_context_bools!(data, user, community);
|
||||
|
||||
context.insert("post", &post);
|
||||
context.insert("replies", &feed);
|
||||
|
@ -269,7 +306,15 @@ pub async fn post_request(
|
|||
.await
|
||||
.unwrap_or(User::deleted()),
|
||||
);
|
||||
community_context(&mut context, &community, is_owner, is_joined, can_post);
|
||||
community_context(
|
||||
&mut context,
|
||||
&community,
|
||||
is_owner,
|
||||
is_joined,
|
||||
is_pending,
|
||||
can_post,
|
||||
can_read,
|
||||
);
|
||||
|
||||
// return
|
||||
Ok(Html(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue