add: ability to transfer community ownership
This commit is contained in:
parent
d42375441f
commit
0c814e95d7
5 changed files with 139 additions and 2 deletions
|
@ -68,6 +68,11 @@
|
||||||
async function create_community_from_form(e) {
|
async function create_community_from_form(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await trigger("atto::debounce", ["communities::create"]);
|
await trigger("atto::debounce", ["communities::create"]);
|
||||||
|
|
||||||
|
if (e.target.title.value.includes(" ")) {
|
||||||
|
return alert("Cannot contain spaces!");
|
||||||
|
}
|
||||||
|
|
||||||
fetch("/api/v1/communities", {
|
fetch("/api/v1/communities", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -317,6 +317,33 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
globalThis.transfer_ownership = async (uid) => {
|
||||||
|
if (
|
||||||
|
!(await trigger("atto::confirm", [
|
||||||
|
"Are you sure you would like to do this?\n\nThis action is PERMANENT!",
|
||||||
|
]))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`/api/v1/communities/{{ community.id }}/transfer_ownership`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
user: uid,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((res) => {
|
||||||
|
trigger("atto::toast", [
|
||||||
|
res.ok ? "success" : "error",
|
||||||
|
res.message,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
globalThis.select_user_from_form = (e) => {
|
globalThis.select_user_from_form = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
fetch(
|
fetch(
|
||||||
|
@ -359,6 +386,7 @@
|
||||||
${res.payload.role !== 33 ? `<button class="red quaternary" onclick="update_user_role('${e.target.uid.value}', 33)">Ban</button>` : `<button class="quaternary" onclick="update_user_role('${e.target.uid.value}', 5)">Unban</button>`}
|
${res.payload.role !== 33 ? `<button class="red quaternary" onclick="update_user_role('${e.target.uid.value}', 33)">Ban</button>` : `<button class="quaternary" onclick="update_user_role('${e.target.uid.value}', 5)">Unban</button>`}
|
||||||
${res.payload.role !== 65 ? `<button class="red quaternary" onclick="update_user_role('${e.target.uid.value}', 65)">Send to review</button>` : `<button class="green quaternary" onclick="update_user_role('${e.target.uid.value}', 5)">Accept join request</button>`}
|
${res.payload.role !== 65 ? `<button class="red quaternary" onclick="update_user_role('${e.target.uid.value}', 65)">Send to review</button>` : `<button class="green quaternary" onclick="update_user_role('${e.target.uid.value}', 5)">Accept join request</button>`}
|
||||||
<button class="red quaternary" onclick="kick_user('${e.target.uid.value}')">Kick</button>
|
<button class="red quaternary" onclick="kick_user('${e.target.uid.value}')">Kick</button>
|
||||||
|
<button class="red quaternary" onclick="transfer_ownership('${e.target.uid.value}')">Transfer ownership</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2" ui_ident="permissions" id="permissions">
|
<div class="flex flex-col gap-2" ui_ident="permissions" id="permissions">
|
||||||
|
|
|
@ -12,12 +12,13 @@ use tetratto_core::model::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
State, get_user_from_token,
|
get_user_from_token,
|
||||||
routes::api::v1::{
|
routes::api::v1::{
|
||||||
CreateCommunity, UpdateCommunityContext, UpdateCommunityJoinAccess,
|
CreateCommunity, UpdateCommunityContext, UpdateCommunityJoinAccess, UpdateCommunityOwner,
|
||||||
UpdateCommunityReadAccess, UpdateCommunityTitle, UpdateCommunityWriteAccess,
|
UpdateCommunityReadAccess, UpdateCommunityTitle, UpdateCommunityWriteAccess,
|
||||||
UpdateMembershipRole,
|
UpdateMembershipRole,
|
||||||
},
|
},
|
||||||
|
State,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn redirect_from_id(
|
pub async fn redirect_from_id(
|
||||||
|
@ -201,6 +202,38 @@ pub async fn update_join_access_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update_owner_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Path(id): Path<usize>,
|
||||||
|
Json(req): Json<UpdateCommunityOwner>,
|
||||||
|
) -> 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_owner(
|
||||||
|
id,
|
||||||
|
user,
|
||||||
|
match req.user.parse::<usize>() {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Json(Error::MiscError(e.to_string()).into()),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "Community updated".to_string(),
|
||||||
|
payload: (),
|
||||||
|
}),
|
||||||
|
Err(e) => Json(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_membership(
|
pub async fn get_membership(
|
||||||
jar: CookieJar,
|
jar: CookieJar,
|
||||||
Extension(data): Extension<State>,
|
Extension(data): Extension<State>,
|
||||||
|
|
|
@ -64,6 +64,10 @@ pub fn routes() -> Router {
|
||||||
"/communities/{id}/access/join",
|
"/communities/{id}/access/join",
|
||||||
post(communities::communities::update_join_access_request),
|
post(communities::communities::update_join_access_request),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/communities/{id}/transfer_ownership",
|
||||||
|
post(communities::communities::update_owner_request),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/communities/{id}/upload/avatar",
|
"/communities/{id}/upload/avatar",
|
||||||
post(communities::images::upload_avatar_request),
|
post(communities::images::upload_avatar_request),
|
||||||
|
@ -342,6 +346,11 @@ pub struct UpdateMembershipRole {
|
||||||
pub role: CommunityPermission,
|
pub role: CommunityPermission,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct UpdateCommunityOwner {
|
||||||
|
pub user: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct UpdateUserRole {
|
pub struct UpdateUserRole {
|
||||||
pub role: FinePermission,
|
pub role: FinePermission,
|
||||||
|
|
|
@ -397,6 +397,68 @@ impl DataManager {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update_community_owner(
|
||||||
|
&self,
|
||||||
|
id: usize,
|
||||||
|
user: User,
|
||||||
|
new_owner: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
let y = self.get_community_by_id(id).await?;
|
||||||
|
|
||||||
|
if user.id != y.owner {
|
||||||
|
if !user.permissions.check(FinePermission::MANAGE_COMMUNITIES) {
|
||||||
|
return Err(Error::NotAllowed);
|
||||||
|
} else {
|
||||||
|
self.create_audit_log_entry(crate::model::moderation::AuditLogEntry::new(
|
||||||
|
user.id,
|
||||||
|
format!("invoked `update_community_owner` with x value `{id}`"),
|
||||||
|
))
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_owner_membership = self
|
||||||
|
.get_membership_by_owner_community(new_owner, y.id)
|
||||||
|
.await?;
|
||||||
|
let current_owner_membership = self
|
||||||
|
.get_membership_by_owner_community(y.owner, y.id)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
let conn = match self.connect().await {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = execute!(
|
||||||
|
&conn,
|
||||||
|
"UPDATE communities SET owner = $1 WHERE id = $2",
|
||||||
|
params![&(new_owner as i64), &(id as i64)]
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
return Err(Error::DatabaseError(e.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cache_clear_community(&y).await;
|
||||||
|
|
||||||
|
// update memberships
|
||||||
|
self.update_membership_role(
|
||||||
|
new_owner_membership.id,
|
||||||
|
CommunityPermission::DEFAULT | CommunityPermission::ADMINISTRATOR,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.update_membership_role(
|
||||||
|
current_owner_membership.id,
|
||||||
|
CommunityPermission::DEFAULT | CommunityPermission::MEMBER,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// return
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
auto_method!(update_community_context(CommunityContext)@get_community_by_id_no_void:MANAGE_COMMUNITIES -> "UPDATE communities SET context = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_community);
|
auto_method!(update_community_context(CommunityContext)@get_community_by_id_no_void:MANAGE_COMMUNITIES -> "UPDATE communities SET context = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_community);
|
||||||
auto_method!(update_community_read_access(CommunityReadAccess)@get_community_by_id_no_void:MANAGE_COMMUNITIES -> "UPDATE communities SET read_access = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_community);
|
auto_method!(update_community_read_access(CommunityReadAccess)@get_community_by_id_no_void:MANAGE_COMMUNITIES -> "UPDATE communities SET read_access = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_community);
|
||||||
auto_method!(update_community_write_access(CommunityWriteAccess)@get_community_by_id_no_void:MANAGE_COMMUNITIES -> "UPDATE communities SET write_access = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_community);
|
auto_method!(update_community_write_access(CommunityWriteAccess)@get_community_by_id_no_void:MANAGE_COMMUNITIES -> "UPDATE communities SET write_access = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_community);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue