This commit is contained in:
Mateusz Gruszczyński committed 2026-10-12 12:19:33 +02:00
1 parent acfe926066
commit df403c0aa7
26 files changed
+1502 -144

No files matched your search

+64 -6
View File
@@ -1791,6 +1791,69 @@ pub async fn remove_resource_user(
Ok(Json(serde_json::json!({"ok":true})))
}
/// Return only explicitly authorized account names; never expose e-mail addresses.
/// The requester must themselves own the resource or have an accepted direct share.
pub async fn resource_mentions(
State(state): State<SharedState>,
headers: HeaderMap,
Query(params): Query<std::collections::HashMap<String, String>>,
) -> Result<Json<serde_json::Value>, AuthError> {
let user = require_user(&state, &headers).await?;
let kind = params.get("kind").map(String::as_str).unwrap_or("");
let slug = params.get("slug").map(String::as_str).unwrap_or("").trim();
let (query, owner_query) = match kind {
"workspace" => (
queries::RESOURCE_MENTION_USERS_WORKSPACE,
queries::USER_OWNS_WORKSPACE,
),
"pad" => (queries::RESOURCE_MENTION_USERS_PAD, queries::USER_OWNS_PAD),
_ => return Err(AuthError::bad_request("Unknown resource type.")),
};
if slug.is_empty() {
return Err(AuthError::bad_request("Missing slug."));
}
let owned: i64 = sqlx::query_scalar(queries::get(state.db.kind(), owner_query))
.bind(user.id)
.bind(slug)
.fetch_one(state.db.pool())
.await
.map_err(AuthError::database)?;
if owned == 0 {
let access: Option<String> = sqlx::query_scalar(queries::get(
state.db.kind(),
queries::RESOURCE_PERMISSION_BY_USER,
))
.bind(kind)
.bind(slug)
.bind(user.id)
.fetch_optional(state.db.pool())
.await
.map_err(AuthError::database)?;
if access.is_none() {
return Err(AuthError::forbidden(
"This resource was not shared with your account.",
));
}
}
let rows = sqlx::query(queries::get(state.db.kind(), query))
.bind(slug)
.bind(kind)
.bind(slug)
.fetch_all(state.db.pool())
.await
.map_err(AuthError::database)?;
let users: Vec<_> = rows
.iter()
.map(|row| -> Result<serde_json::Value, AuthError> {
Ok(serde_json::json!({
"nickname": crate::row_decode::text(row, 0).map_err(AuthError::database)?,
"color": crate::row_decode::optional_text(row, 1).map_err(AuthError::database)?,
}))
})
.collect::<Result<_, _>>()?;
Ok(Json(serde_json::json!({ "users": users })))
}
pub async fn resource_sharing(
State(state): State<SharedState>,
headers: HeaderMap,
@@ -2262,12 +2325,7 @@ pub async fn logout(
let mut revoked_access_tokens = 0_u64;
if session_token.is_some() || has_access_tokens {
let mut tx = state
.db
.pool()
.begin()
.await
.map_err(AuthError::database)?;
let mut tx = state.db.pool().begin().await.map_err(AuthError::database)?;
if let Some(token) = session_token.as_deref() {
let result = sqlx::query(queries::get(