add: channels/messages scopes and api endpoints
This commit is contained in:
parent
8f16068a34
commit
b29760d7ec
10 changed files with 195 additions and 63 deletions
|
@ -536,7 +536,6 @@
|
||||||
method: \"Headers\",
|
method: \"Headers\",
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
// SocketHeaders
|
// SocketHeaders
|
||||||
user: \"{{ user.id }}\",
|
|
||||||
is_channel: window.SUBSCRIBE_CHANNEL,
|
is_channel: window.SUBSCRIBE_CHANNEL,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
(text "{{ icon \"trash\" }}")
|
(text "{{ icon \"trash\" }}")
|
||||||
(span
|
(span
|
||||||
(text "{{ text \"general:action.delete\" }}")))
|
(text "{{ text \"general:action.delete\" }}")))
|
||||||
(text "{% else %}")
|
(text "{% elif selected_community == 0 %}")
|
||||||
(button
|
(button
|
||||||
("onclick" "kick_member('{{ channel.id }}', '{{ user.id }}')")
|
("onclick" "kick_member('{{ channel.id }}', '{{ user.id }}')")
|
||||||
("class" "red")
|
("class" "red")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use tetratto_core::model::{channels::Channel, ApiReturn, Error};
|
use tetratto_core::model::{oauth, channels::Channel, ApiReturn, Error};
|
||||||
use crate::{
|
use crate::{
|
||||||
get_user_from_token,
|
get_user_from_token,
|
||||||
routes::api::v1::{
|
routes::api::v1::{
|
||||||
|
@ -15,7 +15,7 @@ pub async fn create_request(
|
||||||
Json(req): Json<CreateChannel>,
|
Json(req): Json<CreateChannel>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityCreateChannels) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -47,7 +47,7 @@ pub async fn create_group_request(
|
||||||
Json(req): Json<CreateGroupChannel>,
|
Json(req): Json<CreateGroupChannel>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -111,7 +111,7 @@ pub async fn delete_request(
|
||||||
Path(id): Path<usize>,
|
Path(id): Path<usize>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -133,7 +133,7 @@ pub async fn update_title_request(
|
||||||
Json(req): Json<UpdateChannelTitle>,
|
Json(req): Json<UpdateChannelTitle>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -155,7 +155,7 @@ pub async fn update_position_request(
|
||||||
Json(req): Json<UpdateChannelPosition>,
|
Json(req): Json<UpdateChannelPosition>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -177,7 +177,7 @@ pub async fn add_member_request(
|
||||||
Json(req): Json<KickMember>,
|
Json(req): Json<KickMember>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -199,7 +199,7 @@ pub async fn kick_member_request(
|
||||||
Json(req): Json<KickMember>,
|
Json(req): Json<KickMember>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -223,3 +223,73 @@ pub async fn kick_member_request(
|
||||||
Err(e) => Json(e.into()),
|
Err(e) => Json(e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_dm_channels_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let data = &(data.read().await).0;
|
||||||
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels) {
|
||||||
|
Some(ua) => ua,
|
||||||
|
None => return Json(Error::NotAllowed.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match data.get_channels_by_user(user.id).await {
|
||||||
|
Ok(c) => Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "Success".to_string(),
|
||||||
|
payload: Some(c),
|
||||||
|
}),
|
||||||
|
Err(e) => Json(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_community_channels_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, oauth::AppScope::CommunityManageChannels) {
|
||||||
|
Some(ua) => ua,
|
||||||
|
None => return Json(Error::NotAllowed.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if data
|
||||||
|
.get_membership_by_owner_community_no_void(user.id, id)
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
// must be a member of the community to request channels
|
||||||
|
return Json(Error::NotAllowed.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
match data.get_channels_by_community(id).await {
|
||||||
|
Ok(c) => Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "Success".to_string(),
|
||||||
|
payload: Some(c),
|
||||||
|
}),
|
||||||
|
Err(e) => Json(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Path(id): Path<usize>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let data = &(data.read().await).0;
|
||||||
|
if get_user_from_token!(jar, data, oauth::AppScope::CommunityManageChannels).is_none() {
|
||||||
|
return Json(Error::NotAllowed.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
match data.get_channel_by_id(id).await {
|
||||||
|
Ok(c) => Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "Success".to_string(),
|
||||||
|
payload: Some(c),
|
||||||
|
}),
|
||||||
|
Err(e) => Json(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,15 +2,16 @@ use std::{collections::HashMap, time::Duration};
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{
|
extract::{
|
||||||
ws::{Message as WsMessage, WebSocket, WebSocketUpgrade},
|
ws::{Message as WsMessage, WebSocket, WebSocketUpgrade},
|
||||||
Path,
|
Path, Query,
|
||||||
},
|
},
|
||||||
response::{IntoResponse, Response},
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
cache::{Cache, redis::Commands},
|
cache::{Cache, redis::Commands},
|
||||||
model::{
|
model::{
|
||||||
|
oauth,
|
||||||
auth::User,
|
auth::User,
|
||||||
channels::Message,
|
channels::Message,
|
||||||
socket::{PacketType, SocketMessage, SocketMethod},
|
socket::{PacketType, SocketMessage, SocketMethod},
|
||||||
|
@ -18,36 +19,42 @@ use tetratto_core::{
|
||||||
},
|
},
|
||||||
DataManager,
|
DataManager,
|
||||||
};
|
};
|
||||||
use crate::{get_user_from_token, routes::api::v1::CreateMessage, State};
|
use crate::{
|
||||||
|
get_user_from_token,
|
||||||
|
routes::{api::v1::CreateMessage, pages::PaginatedQuery},
|
||||||
|
State,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use futures_util::{sink::SinkExt, stream::StreamExt};
|
use futures_util::{sink::SinkExt, stream::StreamExt};
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
pub struct SocketHeaders {
|
pub struct SocketHeaders {
|
||||||
pub user: String,
|
|
||||||
pub is_channel: bool,
|
pub is_channel: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a subscription to the websocket.
|
/// Handle a subscription to the websocket.
|
||||||
pub async fn subscription_handler(
|
pub async fn subscription_handler(
|
||||||
|
jar: CookieJar,
|
||||||
ws: WebSocketUpgrade,
|
ws: WebSocketUpgrade,
|
||||||
Extension(data): Extension<State>,
|
Extension(data): Extension<State>,
|
||||||
Path(id): Path<String>,
|
Path(id): Path<String>,
|
||||||
) -> Response {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await);
|
let data = &(data.read().await).0;
|
||||||
let data = data.0.clone();
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReadSockets) {
|
||||||
|
Some(ua) => ua,
|
||||||
|
None => return Err(Error::NotAllowed.to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
ws.on_upgrade(|socket| async move {
|
let data = data.clone();
|
||||||
|
Ok(ws.on_upgrade(|socket| async move {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
handle_socket(socket, data, id).await;
|
handle_socket(socket, data, id, user).await;
|
||||||
});
|
});
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: String) {
|
pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: String, user: User) {
|
||||||
let (mut sink, mut stream) = socket.split();
|
let (mut sink, mut stream) = socket.split();
|
||||||
|
|
||||||
let mut user: Option<User> = None;
|
|
||||||
let mut headers: Option<SocketHeaders> = None;
|
let mut headers: Option<SocketHeaders> = None;
|
||||||
|
|
||||||
let channel_id = format!("chats/{community_id}");
|
let channel_id = format!("chats/{community_id}");
|
||||||
|
@ -63,7 +70,7 @@ pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: Str
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if data.method != SocketMethod::Headers && user.is_none() && headers.is_none() {
|
if data.method != SocketMethod::Headers && headers.is_none() {
|
||||||
// we've sent something else before authenticating... that's not right
|
// we've sent something else before authenticating... that's not right
|
||||||
let _ = sink.close().await;
|
let _ = sink.close().await;
|
||||||
return;
|
return;
|
||||||
|
@ -74,24 +81,6 @@ pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: Str
|
||||||
let data: SocketHeaders = data.data();
|
let data: SocketHeaders = data.data();
|
||||||
|
|
||||||
headers = Some(data.clone());
|
headers = Some(data.clone());
|
||||||
user = Some(
|
|
||||||
match dbc
|
|
||||||
.get_user_by_id(match data.user.parse::<usize>() {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(_) => {
|
|
||||||
let _ = sink.close().await;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(ua) => ua,
|
|
||||||
Err(_) => {
|
|
||||||
let _ = sink.close().await;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if data.is_channel {
|
if data.is_channel {
|
||||||
// verify permissions for single channel
|
// verify permissions for single channel
|
||||||
|
@ -112,8 +101,6 @@ pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: Str
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let user = user.as_ref().unwrap();
|
|
||||||
|
|
||||||
let membership = match dbc
|
let membership = match dbc
|
||||||
.get_membership_by_owner_community(user.id, channel.id)
|
.get_membership_by_owner_community(user.id, channel.id)
|
||||||
.await
|
.await
|
||||||
|
@ -142,7 +129,6 @@ pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: Str
|
||||||
}
|
}
|
||||||
|
|
||||||
// get channel permissions
|
// get channel permissions
|
||||||
let user = user.unwrap();
|
|
||||||
let headers = headers.unwrap();
|
let headers = headers.unwrap();
|
||||||
|
|
||||||
let mut channel_read_statuses: HashMap<usize, bool> = HashMap::new();
|
let mut channel_read_statuses: HashMap<usize, bool> = HashMap::new();
|
||||||
|
@ -280,7 +266,7 @@ pub async fn create_request(
|
||||||
Json(req): Json<CreateMessage>,
|
Json(req): Json<CreateMessage>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserCreateMessages) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -311,7 +297,7 @@ pub async fn delete_request(
|
||||||
Path(id): Path<usize>,
|
Path(id): Path<usize>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserDeleteMessages) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -325,3 +311,42 @@ pub async fn delete_request(
|
||||||
Err(e) => Json(e.into()),
|
Err(e) => Json(e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn from_channel_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Path(id): Path<usize>,
|
||||||
|
Query(props): Query<PaginatedQuery>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let data = &(data.read().await).0;
|
||||||
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserCreateMessages) {
|
||||||
|
Some(ua) => ua,
|
||||||
|
None => return Json(Error::NotAllowed.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let channel = match data.get_channel_by_id(id).await {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => return Json(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let membership = match data
|
||||||
|
.get_membership_by_owner_community(user.id, channel.community)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(e) => return Json(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !channel.check_read(user.id, Some(membership.role)) {
|
||||||
|
return Json(Error::NotAllowed.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
match data.get_messages_by_channel(id, 24, props.page).await {
|
||||||
|
Ok(m) => Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "Success".to_string(),
|
||||||
|
payload: Some(m),
|
||||||
|
}),
|
||||||
|
Err(e) => Json(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -433,6 +433,15 @@ pub fn routes() -> Router {
|
||||||
"/channels/{id}/kick",
|
"/channels/{id}/kick",
|
||||||
post(channels::channels::kick_member_request),
|
post(channels::channels::kick_member_request),
|
||||||
)
|
)
|
||||||
|
.route("/channels/{id}", get(channels::channels::get_request))
|
||||||
|
.route(
|
||||||
|
"/channels/community/{id}",
|
||||||
|
get(channels::channels::get_community_channels_request),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/channels/dms",
|
||||||
|
get(channels::channels::get_dm_channels_request),
|
||||||
|
)
|
||||||
// messages
|
// messages
|
||||||
.route(
|
.route(
|
||||||
"/_connect/{id}",
|
"/_connect/{id}",
|
||||||
|
@ -440,6 +449,10 @@ pub fn routes() -> Router {
|
||||||
)
|
)
|
||||||
.route("/messages", post(channels::messages::create_request))
|
.route("/messages", post(channels::messages::create_request))
|
||||||
.route("/messages/{id}", delete(channels::messages::delete_request))
|
.route("/messages/{id}", delete(channels::messages::delete_request))
|
||||||
|
.route(
|
||||||
|
"/messages/from_channel/{id}",
|
||||||
|
get(channels::messages::from_channel_request),
|
||||||
|
)
|
||||||
// emojis
|
// emojis
|
||||||
.route(
|
.route(
|
||||||
"/lookup_emoji",
|
"/lookup_emoji",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{State, get_user_from_token, routes::api::v1::CreateReaction};
|
use crate::{State, get_user_from_token, routes::api::v1::CreateReaction};
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use tetratto_core::model::{ApiReturn, Error, reactions::Reaction};
|
use tetratto_core::model::{oauth, ApiReturn, Error, reactions::Reaction};
|
||||||
|
|
||||||
pub async fn get_request(
|
pub async fn get_request(
|
||||||
jar: CookieJar,
|
jar: CookieJar,
|
||||||
|
@ -9,7 +9,7 @@ pub async fn get_request(
|
||||||
Path(id): Path<usize>,
|
Path(id): Path<usize>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReact) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@ pub async fn create_request(
|
||||||
Json(req): Json<CreateReaction>,
|
Json(req): Json<CreateReaction>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReact) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -81,7 +81,7 @@ pub async fn delete_request(
|
||||||
Path(id): Path<usize>,
|
Path(id): Path<usize>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReact) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{State, get_user_from_token};
|
use crate::{State, get_user_from_token};
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use tetratto_core::model::{stacks::UserStack, ApiReturn, Error};
|
use tetratto_core::model::{oauth, stacks::UserStack, ApiReturn, Error};
|
||||||
use super::{
|
use super::{
|
||||||
AddOrRemoveStackUser, CreateStack, UpdateStackMode, UpdateStackName, UpdateStackPrivacy,
|
AddOrRemoveStackUser, CreateStack, UpdateStackMode, UpdateStackName, UpdateStackPrivacy,
|
||||||
UpdateStackSort,
|
UpdateStackSort,
|
||||||
|
@ -13,7 +13,7 @@ pub async fn create_request(
|
||||||
Json(req): Json<CreateStack>,
|
Json(req): Json<CreateStack>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserCreateStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -38,7 +38,7 @@ pub async fn update_name_request(
|
||||||
Json(req): Json<UpdateStackName>,
|
Json(req): Json<UpdateStackName>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -60,7 +60,7 @@ pub async fn update_privacy_request(
|
||||||
Json(req): Json<UpdateStackPrivacy>,
|
Json(req): Json<UpdateStackPrivacy>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -82,7 +82,7 @@ pub async fn update_mode_request(
|
||||||
Json(req): Json<UpdateStackMode>,
|
Json(req): Json<UpdateStackMode>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -104,7 +104,7 @@ pub async fn update_sort_request(
|
||||||
Json(req): Json<UpdateStackSort>,
|
Json(req): Json<UpdateStackSort>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -126,7 +126,7 @@ pub async fn add_user_request(
|
||||||
Json(req): Json<AddOrRemoveStackUser>,
|
Json(req): Json<AddOrRemoveStackUser>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -169,7 +169,7 @@ pub async fn remove_user_request(
|
||||||
Json(req): Json<AddOrRemoveStackUser>,
|
Json(req): Json<AddOrRemoveStackUser>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
@ -207,7 +207,7 @@ pub async fn delete_request(
|
||||||
Path(id): Path<usize>,
|
Path(id): Path<usize>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum_extra::extract::CookieJar;
|
||||||
use pathbufd::PathBufD;
|
use pathbufd::PathBufD;
|
||||||
use crate::{get_user_from_token, State};
|
use crate::{get_user_from_token, State};
|
||||||
use super::auth::images::read_image;
|
use super::auth::images::read_image;
|
||||||
use tetratto_core::model::{ApiReturn, Error};
|
use tetratto_core::model::{oauth, ApiReturn, Error};
|
||||||
|
|
||||||
pub async fn get_request(
|
pub async fn get_request(
|
||||||
Path(id): Path<usize>,
|
Path(id): Path<usize>,
|
||||||
|
@ -38,7 +38,7 @@ pub async fn delete_request(
|
||||||
Path(id): Path<usize>,
|
Path(id): Path<usize>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
let user = match get_user_from_token!(jar, data) {
|
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageUploads) {
|
||||||
Some(ua) => ua,
|
Some(ua) => ua,
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -159,6 +159,11 @@ pub async fn stream_request(
|
||||||
|
|
||||||
let ignore_users = crate::ignore_users_gen!(user!, data);
|
let ignore_users = crate::ignore_users_gen!(user!, data);
|
||||||
|
|
||||||
|
let channel = match data.0.get_channel_by_id(channel).await {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
|
};
|
||||||
|
|
||||||
let membership = match data
|
let membership = match data
|
||||||
.0
|
.0
|
||||||
.get_membership_by_owner_community(user.id, community)
|
.get_membership_by_owner_community(user.id, community)
|
||||||
|
@ -168,13 +173,19 @@ pub async fn stream_request(
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !channel.check_read(user.id, Some(membership.role)) {
|
||||||
|
return Err(Html(
|
||||||
|
render_error(Error::NotAllowed, &jar, &data, &Some(user)).await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let can_manage_messages = membership.role.check(CommunityPermission::MANAGE_MESSAGES)
|
let can_manage_messages = membership.role.check(CommunityPermission::MANAGE_MESSAGES)
|
||||||
| user.permissions.check(FinePermission::MANAGE_MESSAGES);
|
| user.permissions.check(FinePermission::MANAGE_MESSAGES);
|
||||||
|
|
||||||
let messages = if props.message == 0 {
|
let messages = if props.message == 0 {
|
||||||
match data
|
match data
|
||||||
.0
|
.0
|
||||||
.get_messages_by_channel(channel, 24, props.page)
|
.get_messages_by_channel(channel.id, 24, props.page)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(p) => match data.0.fill_messages(p, &ignore_users).await {
|
Ok(p) => match data.0.fill_messages(p, &ignore_users).await {
|
||||||
|
|
|
@ -70,6 +70,8 @@ pub enum AppScope {
|
||||||
UserCreateDrafts,
|
UserCreateDrafts,
|
||||||
/// Create communities on behalf of the user.
|
/// Create communities on behalf of the user.
|
||||||
UserCreateCommunities,
|
UserCreateCommunities,
|
||||||
|
/// Create stacks on behalf of the user.
|
||||||
|
UserCreateStacks,
|
||||||
/// Delete posts owned by the user.
|
/// Delete posts owned by the user.
|
||||||
UserDeletePosts,
|
UserDeletePosts,
|
||||||
/// Delete messages owned by the user.
|
/// Delete messages owned by the user.
|
||||||
|
@ -98,12 +100,16 @@ pub enum AppScope {
|
||||||
UserManageNotifications,
|
UserManageNotifications,
|
||||||
/// Manage the user's requests.
|
/// Manage the user's requests.
|
||||||
UserManageRequests,
|
UserManageRequests,
|
||||||
|
/// Manage the user's uploads.
|
||||||
|
UserManageUploads,
|
||||||
/// Edit posts created by the user.
|
/// Edit posts created by the user.
|
||||||
UserEditPosts,
|
UserEditPosts,
|
||||||
/// Edit drafts created by the user.
|
/// Edit drafts created by the user.
|
||||||
UserEditDrafts,
|
UserEditDrafts,
|
||||||
/// Vote in polls as the user.
|
/// Vote in polls as the user.
|
||||||
UserVote,
|
UserVote,
|
||||||
|
/// React to posts on behalf of the user. Also allows the removal of reactions.
|
||||||
|
UserReact,
|
||||||
/// Join communities on behalf of the user.
|
/// Join communities on behalf of the user.
|
||||||
UserJoinCommunities,
|
UserJoinCommunities,
|
||||||
/// Permanently delete posts.
|
/// Permanently delete posts.
|
||||||
|
@ -126,6 +132,10 @@ pub enum AppScope {
|
||||||
CommunityTransferOwnership,
|
CommunityTransferOwnership,
|
||||||
/// Read the membership of users in communities owned by the current user.
|
/// Read the membership of users in communities owned by the current user.
|
||||||
CommunityReadMemberships,
|
CommunityReadMemberships,
|
||||||
|
/// Create channels in the user's communities.
|
||||||
|
CommunityCreateChannels,
|
||||||
|
/// Manage channels in the user's communities.
|
||||||
|
CommunityManageChannels,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppScope {
|
impl AppScope {
|
||||||
|
@ -164,9 +174,11 @@ impl AppScope {
|
||||||
"user-manage-blocks" => Self::UserManageBlocks,
|
"user-manage-blocks" => Self::UserManageBlocks,
|
||||||
"user-manage-notifications" => Self::UserManageNotifications,
|
"user-manage-notifications" => Self::UserManageNotifications,
|
||||||
"user-manage-requests" => Self::UserManageRequests,
|
"user-manage-requests" => Self::UserManageRequests,
|
||||||
|
"user-manage-uploads" => Self::UserManageUploads,
|
||||||
"user-edit-posts" => Self::UserEditPosts,
|
"user-edit-posts" => Self::UserEditPosts,
|
||||||
"user-edit-drafts" => Self::UserEditDrafts,
|
"user-edit-drafts" => Self::UserEditDrafts,
|
||||||
"user-vote" => Self::UserVote,
|
"user-vote" => Self::UserVote,
|
||||||
|
"user-react" => Self::UserReact,
|
||||||
"user-join-communities" => Self::UserJoinCommunities,
|
"user-join-communities" => Self::UserJoinCommunities,
|
||||||
"mod-purge-posts" => Self::ModPurgePosts,
|
"mod-purge-posts" => Self::ModPurgePosts,
|
||||||
"mod-delete-posts" => Self::ModDeletePosts,
|
"mod-delete-posts" => Self::ModDeletePosts,
|
||||||
|
@ -178,6 +190,8 @@ impl AppScope {
|
||||||
"community-manage" => Self::CommunityManage,
|
"community-manage" => Self::CommunityManage,
|
||||||
"community-transfer-ownership" => Self::CommunityTransferOwnership,
|
"community-transfer-ownership" => Self::CommunityTransferOwnership,
|
||||||
"community-read-memberships" => Self::CommunityReadMemberships,
|
"community-read-memberships" => Self::CommunityReadMemberships,
|
||||||
|
"community-create-channels" => Self::CommunityCreateChannels,
|
||||||
|
"community-manage-channels" => Self::CommunityManageChannels,
|
||||||
_ => continue,
|
_ => continue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue