This commit is contained in:
Mateusz Gruszczyński
2026-07-28 16:24:15 +02:00
parent d37f7f6ad2
commit eaacd54973
8 changed files with 59 additions and 30 deletions
@@ -0,0 +1,3 @@
ALTER TABLE users ADD COLUMN directory_username VARCHAR(255);
UPDATE users SET directory_username = nickname WHERE auth_provider IS NOT NULL AND auth_provider <> 'local' AND directory_username IS NULL;
CREATE INDEX idx_users_directory_username ON users (directory_username);
@@ -0,0 +1,3 @@
ALTER TABLE users ADD COLUMN directory_username VARCHAR(255);
UPDATE users SET directory_username = nickname WHERE auth_provider IS NOT NULL AND auth_provider <> 'local' AND directory_username IS NULL;
CREATE INDEX idx_users_directory_username ON users (LOWER(directory_username));
@@ -0,0 +1,3 @@
ALTER TABLE users ADD COLUMN directory_username TEXT;
UPDATE users SET directory_username = nickname WHERE auth_provider IS NOT NULL AND auth_provider <> 'local' AND directory_username IS NULL;
CREATE INDEX idx_users_directory_username ON users (directory_username);
+2
View File
@@ -300,6 +300,7 @@ async fn provision_ldap_user(
.bind(&identity.external_id) .bind(&identity.external_id)
.bind(&identity.external_dn) .bind(&identity.external_dn)
.bind(&identity.display_name) .bind(&identity.display_name)
.bind(&identity.username)
.execute(state.db.pool()) .execute(state.db.pool())
.await .await
.map_err(AuthError::database)?; .map_err(AuthError::database)?;
@@ -328,6 +329,7 @@ async fn sync_directory_user(
.bind(&identity.external_id) .bind(&identity.external_id)
.bind(&identity.external_dn) .bind(&identity.external_dn)
.bind(&identity.display_name) .bind(&identity.display_name)
.bind(&identity.username)
.bind(Utc::now().to_rfc3339()) .bind(Utc::now().to_rfc3339())
.bind(user.id) .bind(user.id)
.execute(state.db.pool()) .execute(state.db.pool())
+32 -14
View File
@@ -537,7 +537,7 @@ pub async fn confirm_account(
let now_time = Utc::now(); let now_time = Utc::now();
let now = now_time.to_rfc3339(); let now = now_time.to_rfc3339();
let token_hash = hash_token(req.token.trim()); let token_hash = hash_token(req.token.trim());
let row: Option<(i64, String, Option<String>)> = sqlx::query_as(queries::get( let row = sqlx::query(queries::get(
state.db.kind(), state.db.kind(),
queries::AUTH_FIND_CONFIRMATION_TOKEN, queries::AUTH_FIND_CONFIRMATION_TOKEN,
)) ))
@@ -545,9 +545,12 @@ pub async fn confirm_account(
.fetch_optional(state.db.pool()) .fetch_optional(state.db.pool())
.await .await
.map_err(AuthError::database)?; .map_err(AuthError::database)?;
let (user_id, expires_at, used_at) = row.ok_or_else(|| { let row = row.ok_or_else(|| {
AuthError::bad_request("The confirmation link is invalid or has expired.") AuthError::bad_request("The confirmation link is invalid or has expired.")
})?; })?;
let user_id: i64 = row.try_get(0).map_err(AuthError::database)?;
let expires_at = crate::row_decode::text(&row, 1).map_err(AuthError::database)?;
let used_at = crate::row_decode::optional_text(&row, 2).map_err(AuthError::database)?;
let expires_at = chrono::DateTime::parse_from_rfc3339(&expires_at) let expires_at = chrono::DateTime::parse_from_rfc3339(&expires_at)
.map_err(|_| AuthError::bad_request("The confirmation link is invalid or has expired."))? .map_err(|_| AuthError::bad_request("The confirmation link is invalid or has expired."))?
.with_timezone(&Utc); .with_timezone(&Utc);
@@ -601,7 +604,7 @@ async fn directory_profile_metadata(
state: &SharedState, state: &SharedState,
user: &User, user: &User,
) -> Result<(bool, Option<String>, Option<String>, Option<String>), AuthError> { ) -> Result<(bool, Option<String>, Option<String>, Option<String>), AuthError> {
let row: Option<(String, Option<String>)> = sqlx::query_as(queries::get( let row = sqlx::query(queries::get(
state.db.kind(), state.db.kind(),
queries::AUTH_DIRECTORY_PROFILE_BY_USER, queries::AUTH_DIRECTORY_PROFILE_BY_USER,
)) ))
@@ -609,9 +612,11 @@ async fn directory_profile_metadata(
.fetch_optional(state.db.pool()) .fetch_optional(state.db.pool())
.await .await
.map_err(AuthError::database)?; .map_err(AuthError::database)?;
let Some((provider, display_name)) = row else { let Some(row) = row else {
return Ok((false, None, None, None)); return Ok((false, None, None, None));
}; };
let provider = crate::row_decode::text(&row, 0).map_err(AuthError::database)?;
let display_name = crate::row_decode::optional_text(&row, 1).map_err(AuthError::database)?;
if provider == "local" { if provider == "local" {
return Ok((false, None, None, None)); return Ok((false, None, None, None));
} }
@@ -842,16 +847,19 @@ pub async fn confirm_account_action(
) -> Result<Json<serde_json::Value>, AuthError> { ) -> Result<Json<serde_json::Value>, AuthError> {
let now = Utc::now(); let now = Utc::now();
let hash = hash_token(req.token.trim()); let hash = hash_token(req.token.trim());
let row: Option<(i64, String, Option<String>, String, Option<String>)> = sqlx::query_as( let row = sqlx::query(queries::get(state.db.kind(), queries::AUTH_ACCOUNT_ACTION_BY_TOKEN))
queries::get(state.db.kind(), queries::AUTH_ACCOUNT_ACTION_BY_TOKEN),
)
.bind(&hash) .bind(&hash)
.fetch_optional(state.db.pool()) .fetch_optional(state.db.pool())
.await .await
.map_err(AuthError::database)?; .map_err(AuthError::database)?;
let (user_id, action, payload, expires_at, used_at) = row.ok_or_else(|| { let row = row.ok_or_else(|| {
AuthError::bad_request("The confirmation link is invalid or has expired.") AuthError::bad_request("The confirmation link is invalid or has expired.")
})?; })?;
let user_id: i64 = row.try_get(0).map_err(AuthError::database)?;
let action = crate::row_decode::text(&row, 1).map_err(AuthError::database)?;
let payload = crate::row_decode::optional_text(&row, 2).map_err(AuthError::database)?;
let expires_at = crate::row_decode::text(&row, 3).map_err(AuthError::database)?;
let used_at = crate::row_decode::optional_text(&row, 4).map_err(AuthError::database)?;
let expires = chrono::DateTime::parse_from_rfc3339(&expires_at) let expires = chrono::DateTime::parse_from_rfc3339(&expires_at)
.map_err(|_| AuthError::bad_request("The confirmation link is invalid or has expired."))? .map_err(|_| AuthError::bad_request("The confirmation link is invalid or has expired."))?
.with_timezone(&Utc); .with_timezone(&Utc);
@@ -1364,16 +1372,23 @@ pub async fn accept_share_invitation(
AxumPath(token): AxumPath<String>, AxumPath(token): AxumPath<String>,
) -> Result<Json<serde_json::Value>, AuthError> { ) -> Result<Json<serde_json::Value>, AuthError> {
let token_hash = hash_token(token.trim()); let token_hash = hash_token(token.trim());
let row: Option<(String, String, i64, String, String, Option<String>)> = sqlx::query_as( let row = sqlx::query(queries::get(
queries::get(state.db.kind(), queries::SHARE_INVITATION_FIND_TOKEN), state.db.kind(),
) queries::SHARE_INVITATION_FIND_TOKEN,
))
.bind(&token_hash) .bind(&token_hash)
.fetch_optional(state.db.pool()) .fetch_optional(state.db.pool())
.await .await
.map_err(AuthError::database)?; .map_err(AuthError::database)?;
let (kind, slug, user_id, permission, expires_at, accepted_at) = row.ok_or_else(|| { let row = row.ok_or_else(|| {
AuthError::bad_request("The sharing invitation is invalid or has expired.") AuthError::bad_request("The sharing invitation is invalid or has expired.")
})?; })?;
let kind = crate::row_decode::text(&row, 0).map_err(AuthError::database)?;
let slug = crate::row_decode::text(&row, 1).map_err(AuthError::database)?;
let user_id: i64 = row.try_get(2).map_err(AuthError::database)?;
let permission = crate::row_decode::text(&row, 3).map_err(AuthError::database)?;
let expires_at = crate::row_decode::text(&row, 4).map_err(AuthError::database)?;
let accepted_at = crate::row_decode::optional_text(&row, 5).map_err(AuthError::database)?;
let expires = chrono::DateTime::parse_from_rfc3339(&expires_at) let expires = chrono::DateTime::parse_from_rfc3339(&expires_at)
.map_err(|_| AuthError::bad_request("The sharing invitation is invalid or has expired."))? .map_err(|_| AuthError::bad_request("The sharing invitation is invalid or has expired."))?
.with_timezone(&Utc); .with_timezone(&Utc);
@@ -1727,7 +1742,7 @@ pub async fn confirm_reset(
let now_time = Utc::now(); let now_time = Utc::now();
let now = now_time.to_rfc3339(); let now = now_time.to_rfc3339();
let token_hash = hash_token(req.token.trim()); let token_hash = hash_token(req.token.trim());
let token_row: Option<(i64, String, Option<String>)> = sqlx::query_as(queries::get( let token_row = sqlx::query(queries::get(
state.db.kind(), state.db.kind(),
queries::AUTH_FIND_RESET_TOKEN, queries::AUTH_FIND_RESET_TOKEN,
)) ))
@@ -1735,8 +1750,11 @@ pub async fn confirm_reset(
.fetch_optional(state.db.pool()) .fetch_optional(state.db.pool())
.await .await
.map_err(AuthError::database)?; .map_err(AuthError::database)?;
let (user_id, expires_at, used_at) = token_row let token_row = token_row
.ok_or_else(|| AuthError::bad_request("The reset link is invalid or has expired."))?; .ok_or_else(|| AuthError::bad_request("The reset link is invalid or has expired."))?;
let user_id: i64 = token_row.try_get(0).map_err(AuthError::database)?;
let expires_at = crate::row_decode::text(&token_row, 1).map_err(AuthError::database)?;
let used_at = crate::row_decode::optional_text(&token_row, 2).map_err(AuthError::database)?;
let expires_at = chrono::DateTime::parse_from_rfc3339(&expires_at) let expires_at = chrono::DateTime::parse_from_rfc3339(&expires_at)
.map_err(|_| AuthError::bad_request("The reset link is invalid or has expired."))? .map_err(|_| AuthError::bad_request("The reset link is invalid or has expired."))?
.with_timezone(&Utc); .with_timezone(&Utc);
+4 -4
View File
@@ -23,12 +23,12 @@ pub fn get(query: Query) -> &'static str {
Query::AUTH_INSERT_ACCOUNT_ACTION => r#"INSERT INTO account_action_tokens (token,user_id,action,payload,expires_at,created_at) VALUES (?, ?, ?, ?, ?, ?)"#, Query::AUTH_INSERT_ACCOUNT_ACTION => r#"INSERT INTO account_action_tokens (token,user_id,action,payload,expires_at,created_at) VALUES (?, ?, ?, ?, ?, ?)"#,
Query::AUTH_DELETE_EXPIRED_UNCONFIRMED_USERS => r#"DELETE FROM users WHERE confirmed_at IS NULL AND created_at < ?"#, Query::AUTH_DELETE_EXPIRED_UNCONFIRMED_USERS => r#"DELETE FROM users WHERE confirmed_at IS NULL AND created_at < ?"#,
Query::AUTH_INSERT_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at) VALUES (?, ?, ?, ?, ?, ?)"#, Query::AUTH_INSERT_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at) VALUES (?, ?, ?, ?, ?, ?)"#,
Query::AUTH_INSERT_DIRECTORY_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at, auth_provider, external_id, external_dn, directory_display_name) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#, Query::AUTH_INSERT_DIRECTORY_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at, auth_provider, external_id, external_dn, directory_display_name, directory_username) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#,
Query::AUTH_UPDATE_DIRECTORY_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, auth_provider = ?, external_id = ?, external_dn = ?, directory_display_name = ?, updated_at = ? WHERE id = ?"#, Query::AUTH_UPDATE_DIRECTORY_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, auth_provider = ?, external_id = ?, external_dn = ?, directory_display_name = ?, directory_username = ?, updated_at = ? WHERE id = ?"#,
Query::AUTH_DIRECTORY_PROFILE_BY_USER => r#"SELECT auth_provider, directory_display_name FROM users WHERE id = ?"#, Query::AUTH_DIRECTORY_PROFILE_BY_USER => r#"SELECT auth_provider, directory_display_name FROM users WHERE id = ?"#,
Query::AUTH_USER_BY_EXTERNAL_ID => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users WHERE auth_provider = ? AND external_id = ?"#, Query::AUTH_USER_BY_EXTERNAL_ID => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users WHERE auth_provider = ? AND external_id = ?"#,
Query::AUTH_DELETE_USER => r#"DELETE FROM users WHERE id = ?"#, Query::AUTH_DELETE_USER => r#"DELETE FROM users WHERE id = ?"#,
Query::AUTH_ANONYMIZE_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, password_hash = ?, is_active = 0, auth_provider = 'deleted', external_id = NULL, external_dn = NULL, directory_display_name = NULL, updated_at = ? WHERE id = ?"#, Query::AUTH_ANONYMIZE_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, password_hash = ?, is_active = 0, auth_provider = 'deleted', external_id = NULL, external_dn = NULL, directory_display_name = NULL, directory_username = NULL, updated_at = ? WHERE id = ?"#,
Query::AUTH_NICKNAME_BY_ID => r#"SELECT nickname FROM users WHERE id = ?"#, Query::AUTH_NICKNAME_BY_ID => r#"SELECT nickname FROM users WHERE id = ?"#,
Query::AUTH_ANONYMIZE_NOTE_CREATORS => r#"UPDATE notes SET created_by = ? WHERE created_by = ?"#, Query::AUTH_ANONYMIZE_NOTE_CREATORS => r#"UPDATE notes SET created_by = ? WHERE created_by = ?"#,
Query::AUTH_SESSION_EXPIRES_AT => r#"SELECT expires_at FROM user_sessions WHERE token = ?"#, Query::AUTH_SESSION_EXPIRES_AT => r#"SELECT expires_at FROM user_sessions WHERE token = ?"#,
@@ -49,7 +49,7 @@ pub fn get(query: Query) -> &'static str {
Query::AUTH_INSERT_SESSION => r#"INSERT INTO user_sessions (token, user_id, expires_at) VALUES (?, ?, ?)"#, Query::AUTH_INSERT_SESSION => r#"INSERT INTO user_sessions (token, user_id, expires_at) VALUES (?, ?, ?)"#,
Query::AUTH_USER_BY_NICKNAME => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users WHERE nickname_key = ?"#, Query::AUTH_USER_BY_NICKNAME => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users WHERE nickname_key = ?"#,
Query::AUTH_USER_BY_EMAIL => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users WHERE email_key = ?"#, Query::AUTH_USER_BY_EMAIL => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users WHERE email_key = ?"#,
Query::AUTH_USER_BY_SHARE_IDENTIFIER => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users JOIN (SELECT ? AS identifier) lookup ON 1 = 1 WHERE is_active = 1 AND (email_key = lookup.identifier OR LOWER(external_id) = lookup.identifier) LIMIT 1"#, Query::AUTH_USER_BY_SHARE_IDENTIFIER => r#"SELECT id, nickname, email, CAST(password_hash AS CHAR CHARACTER SET utf8mb4) AS password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS SIGNED) AS is_active FROM users JOIN (SELECT ? AS identifier) lookup ON 1 = 1 WHERE is_active = 1 AND (email_key = lookup.identifier OR LOWER(directory_username) = lookup.identifier OR LOWER(external_id) = lookup.identifier) LIMIT 1"#,
Query::USER_ATTACH_WORKSPACE => r#"INSERT INTO user_workspaces (user_id, workspace_id) SELECT ?, id FROM workspaces WHERE slug = ?"#, Query::USER_ATTACH_WORKSPACE => r#"INSERT INTO user_workspaces (user_id, workspace_id) SELECT ?, id FROM workspaces WHERE slug = ?"#,
Query::USER_ATTACH_PAD => r#"INSERT INTO user_pads (user_id, pad_id) SELECT ?, id FROM pads WHERE slug = ?"#, Query::USER_ATTACH_PAD => r#"INSERT INTO user_pads (user_id, pad_id) SELECT ?, id FROM pads WHERE slug = ?"#,
Query::USER_LIST_WORKSPACES => r#"SELECT w.slug, CAST(w.title AS CHAR CHARACTER SET utf8mb4) AS title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS protected, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END AS private, 1 AS owned, 'rw' AS permission, '' AS shared_by FROM user_workspaces uw JOIN workspaces w ON w.id = uw.workspace_id WHERE uw.user_id = ? UNION SELECT w.slug, CAST(w.title AS CHAR CHARACTER SET utf8mb4) AS title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END, 0, rp.permission, COALESCE((SELECT u.nickname FROM user_workspaces owner_uw JOIN users u ON u.id = owner_uw.user_id WHERE owner_uw.workspace_id = w.id LIMIT 1), 'Unknown user') AS shared_by FROM resource_permissions rp JOIN workspaces w ON w.slug = rp.resource_slug WHERE rp.resource_kind = 'workspace' AND rp.user_id = ? ORDER BY updated_at DESC"#, Query::USER_LIST_WORKSPACES => r#"SELECT w.slug, CAST(w.title AS CHAR CHARACTER SET utf8mb4) AS title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS protected, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END AS private, 1 AS owned, 'rw' AS permission, '' AS shared_by FROM user_workspaces uw JOIN workspaces w ON w.id = uw.workspace_id WHERE uw.user_id = ? UNION SELECT w.slug, CAST(w.title AS CHAR CHARACTER SET utf8mb4) AS title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END, 0, rp.permission, COALESCE((SELECT u.nickname FROM user_workspaces owner_uw JOIN users u ON u.id = owner_uw.user_id WHERE owner_uw.workspace_id = w.id LIMIT 1), 'Unknown user') AS shared_by FROM resource_permissions rp JOIN workspaces w ON w.slug = rp.resource_slug WHERE rp.resource_kind = 'workspace' AND rp.user_id = ? ORDER BY updated_at DESC"#,
+4 -4
View File
@@ -23,12 +23,12 @@ pub fn get(query: Query) -> &'static str {
Query::AUTH_INSERT_ACCOUNT_ACTION => r#"INSERT INTO account_action_tokens (token,user_id,action,payload,expires_at,created_at) VALUES ($1, $2, $3, $4, $5, $6)"#, Query::AUTH_INSERT_ACCOUNT_ACTION => r#"INSERT INTO account_action_tokens (token,user_id,action,payload,expires_at,created_at) VALUES ($1, $2, $3, $4, $5, $6)"#,
Query::AUTH_DELETE_EXPIRED_UNCONFIRMED_USERS => r#"DELETE FROM users WHERE confirmed_at IS NULL AND created_at < $1"#, Query::AUTH_DELETE_EXPIRED_UNCONFIRMED_USERS => r#"DELETE FROM users WHERE confirmed_at IS NULL AND created_at < $1"#,
Query::AUTH_INSERT_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at) VALUES ($1, $2, $3, $4, $5, $6)"#, Query::AUTH_INSERT_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at) VALUES ($1, $2, $3, $4, $5, $6)"#,
Query::AUTH_INSERT_DIRECTORY_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at, auth_provider, external_id, external_dn, directory_display_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"#, Query::AUTH_INSERT_DIRECTORY_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at, auth_provider, external_id, external_dn, directory_display_name, directory_username) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"#,
Query::AUTH_UPDATE_DIRECTORY_USER => r#"UPDATE users SET nickname = $1, nickname_key = $2, email = $3, email_key = $4, auth_provider = $5, external_id = $6, external_dn = $7, directory_display_name = $8, updated_at = $9 WHERE id = $10"#, Query::AUTH_UPDATE_DIRECTORY_USER => r#"UPDATE users SET nickname = $1, nickname_key = $2, email = $3, email_key = $4, auth_provider = $5, external_id = $6, external_dn = $7, directory_display_name = $8, directory_username = $9, updated_at = $10 WHERE id = $11"#,
Query::AUTH_DIRECTORY_PROFILE_BY_USER => r#"SELECT auth_provider, directory_display_name FROM users WHERE id = $1"#, Query::AUTH_DIRECTORY_PROFILE_BY_USER => r#"SELECT auth_provider, directory_display_name FROM users WHERE id = $1"#,
Query::AUTH_USER_BY_EXTERNAL_ID => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE auth_provider = $1 AND external_id = $2"#, Query::AUTH_USER_BY_EXTERNAL_ID => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE auth_provider = $1 AND external_id = $2"#,
Query::AUTH_DELETE_USER => r#"DELETE FROM users WHERE id = $1"#, Query::AUTH_DELETE_USER => r#"DELETE FROM users WHERE id = $1"#,
Query::AUTH_ANONYMIZE_USER => r#"UPDATE users SET nickname = $1, nickname_key = $2, email = $3, email_key = $4, password_hash = $5, is_active = FALSE, auth_provider = 'deleted', external_id = NULL, external_dn = NULL, directory_display_name = NULL, updated_at = $6 WHERE id = $7"#, Query::AUTH_ANONYMIZE_USER => r#"UPDATE users SET nickname = $1, nickname_key = $2, email = $3, email_key = $4, password_hash = $5, is_active = FALSE, auth_provider = 'deleted', external_id = NULL, external_dn = NULL, directory_display_name = NULL, directory_username = NULL, updated_at = $6 WHERE id = $7"#,
Query::AUTH_NICKNAME_BY_ID => r#"SELECT nickname FROM users WHERE id = $1"#, Query::AUTH_NICKNAME_BY_ID => r#"SELECT nickname FROM users WHERE id = $1"#,
Query::AUTH_ANONYMIZE_NOTE_CREATORS => r#"UPDATE notes SET created_by = $1 WHERE created_by = $2"#, Query::AUTH_ANONYMIZE_NOTE_CREATORS => r#"UPDATE notes SET created_by = $1 WHERE created_by = $2"#,
Query::AUTH_SESSION_EXPIRES_AT => r#"SELECT expires_at FROM user_sessions WHERE token = $1"#, Query::AUTH_SESSION_EXPIRES_AT => r#"SELECT expires_at FROM user_sessions WHERE token = $1"#,
@@ -49,7 +49,7 @@ pub fn get(query: Query) -> &'static str {
Query::AUTH_INSERT_SESSION => r#"INSERT INTO user_sessions (token, user_id, expires_at) VALUES ($1, $2, $3)"#, Query::AUTH_INSERT_SESSION => r#"INSERT INTO user_sessions (token, user_id, expires_at) VALUES ($1, $2, $3)"#,
Query::AUTH_USER_BY_NICKNAME => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE nickname_key = $1"#, Query::AUTH_USER_BY_NICKNAME => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE nickname_key = $1"#,
Query::AUTH_USER_BY_EMAIL => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE email_key = $1"#, Query::AUTH_USER_BY_EMAIL => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE email_key = $1"#,
Query::AUTH_USER_BY_SHARE_IDENTIFIER => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE is_active = TRUE AND (email_key = $1 OR LOWER(external_id) = $1) LIMIT 1"#, Query::AUTH_USER_BY_SHARE_IDENTIFIER => r#"SELECT id, nickname, email, password_hash, confirmed_at, CAST(CASE WHEN is_active THEN 1 ELSE 0 END AS BIGINT) AS is_active FROM users WHERE is_active = TRUE AND (email_key = $1 OR LOWER(directory_username) = $1 OR LOWER(external_id) = $1) LIMIT 1"#,
Query::USER_ATTACH_WORKSPACE => r#"INSERT INTO user_workspaces (user_id, workspace_id) SELECT $1, id FROM workspaces WHERE slug = $2"#, Query::USER_ATTACH_WORKSPACE => r#"INSERT INTO user_workspaces (user_id, workspace_id) SELECT $1, id FROM workspaces WHERE slug = $2"#,
Query::USER_ATTACH_PAD => r#"INSERT INTO user_pads (user_id, pad_id) SELECT $1, id FROM pads WHERE slug = $2"#, Query::USER_ATTACH_PAD => r#"INSERT INTO user_pads (user_id, pad_id) SELECT $1, id FROM pads WHERE slug = $2"#,
Query::USER_LIST_WORKSPACES => r#"SELECT w.slug, w.title, CAST(CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS BIGINT) AS protected, w.updated_at, CAST(CASE WHEN w.is_private THEN 1 ELSE 0 END AS BIGINT) AS private, CAST(1 AS BIGINT) AS owned, 'rw' AS permission, '' AS shared_by FROM user_workspaces uw JOIN workspaces w ON w.id = uw.workspace_id WHERE uw.user_id = $1 UNION SELECT w.slug, w.title, CAST(CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS BIGINT), w.updated_at, CAST(CASE WHEN w.is_private THEN 1 ELSE 0 END AS BIGINT), CAST(0 AS BIGINT), rp.permission, COALESCE((SELECT u.nickname FROM user_workspaces owner_uw JOIN users u ON u.id = owner_uw.user_id WHERE owner_uw.workspace_id = w.id LIMIT 1), 'Unknown user') AS shared_by FROM resource_permissions rp JOIN workspaces w ON w.slug = rp.resource_slug WHERE rp.resource_kind = 'workspace' AND rp.user_id = $2 ORDER BY updated_at DESC"#, Query::USER_LIST_WORKSPACES => r#"SELECT w.slug, w.title, CAST(CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS BIGINT) AS protected, w.updated_at, CAST(CASE WHEN w.is_private THEN 1 ELSE 0 END AS BIGINT) AS private, CAST(1 AS BIGINT) AS owned, 'rw' AS permission, '' AS shared_by FROM user_workspaces uw JOIN workspaces w ON w.id = uw.workspace_id WHERE uw.user_id = $1 UNION SELECT w.slug, w.title, CAST(CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS BIGINT), w.updated_at, CAST(CASE WHEN w.is_private THEN 1 ELSE 0 END AS BIGINT), CAST(0 AS BIGINT), rp.permission, COALESCE((SELECT u.nickname FROM user_workspaces owner_uw JOIN users u ON u.id = owner_uw.user_id WHERE owner_uw.workspace_id = w.id LIMIT 1), 'Unknown user') AS shared_by FROM resource_permissions rp JOIN workspaces w ON w.slug = rp.resource_slug WHERE rp.resource_kind = 'workspace' AND rp.user_id = $2 ORDER BY updated_at DESC"#,
+4 -4
View File
@@ -23,12 +23,12 @@ pub fn get(query: Query) -> &'static str {
Query::AUTH_INSERT_ACCOUNT_ACTION => r#"INSERT INTO account_action_tokens (token,user_id,action,payload,expires_at,created_at) VALUES (?, ?, ?, ?, ?, ?)"#, Query::AUTH_INSERT_ACCOUNT_ACTION => r#"INSERT INTO account_action_tokens (token,user_id,action,payload,expires_at,created_at) VALUES (?, ?, ?, ?, ?, ?)"#,
Query::AUTH_DELETE_EXPIRED_UNCONFIRMED_USERS => r#"DELETE FROM users WHERE confirmed_at IS NULL AND created_at < ?"#, Query::AUTH_DELETE_EXPIRED_UNCONFIRMED_USERS => r#"DELETE FROM users WHERE confirmed_at IS NULL AND created_at < ?"#,
Query::AUTH_INSERT_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at) VALUES (?, ?, ?, ?, ?, ?)"#, Query::AUTH_INSERT_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at) VALUES (?, ?, ?, ?, ?, ?)"#,
Query::AUTH_INSERT_DIRECTORY_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at, auth_provider, external_id, external_dn, directory_display_name) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#, Query::AUTH_INSERT_DIRECTORY_USER => r#"INSERT INTO users (nickname, nickname_key, email, email_key, password_hash, confirmed_at, auth_provider, external_id, external_dn, directory_display_name, directory_username) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#,
Query::AUTH_UPDATE_DIRECTORY_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, auth_provider = ?, external_id = ?, external_dn = ?, directory_display_name = ?, updated_at = ? WHERE id = ?"#, Query::AUTH_UPDATE_DIRECTORY_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, auth_provider = ?, external_id = ?, external_dn = ?, directory_display_name = ?, directory_username = ?, updated_at = ? WHERE id = ?"#,
Query::AUTH_DIRECTORY_PROFILE_BY_USER => r#"SELECT auth_provider, directory_display_name FROM users WHERE id = ?"#, Query::AUTH_DIRECTORY_PROFILE_BY_USER => r#"SELECT auth_provider, directory_display_name FROM users WHERE id = ?"#,
Query::AUTH_USER_BY_EXTERNAL_ID => r#"SELECT id, nickname, email, password_hash, confirmed_at, is_active FROM users WHERE auth_provider = ? AND external_id = ?"#, Query::AUTH_USER_BY_EXTERNAL_ID => r#"SELECT id, nickname, email, password_hash, confirmed_at, is_active FROM users WHERE auth_provider = ? AND external_id = ?"#,
Query::AUTH_DELETE_USER => r#"DELETE FROM users WHERE id = ?"#, Query::AUTH_DELETE_USER => r#"DELETE FROM users WHERE id = ?"#,
Query::AUTH_ANONYMIZE_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, password_hash = ?, is_active = 0, auth_provider = 'deleted', external_id = NULL, external_dn = NULL, directory_display_name = NULL, updated_at = ? WHERE id = ?"#, Query::AUTH_ANONYMIZE_USER => r#"UPDATE users SET nickname = ?, nickname_key = ?, email = ?, email_key = ?, password_hash = ?, is_active = 0, auth_provider = 'deleted', external_id = NULL, external_dn = NULL, directory_display_name = NULL, directory_username = NULL, updated_at = ? WHERE id = ?"#,
Query::AUTH_NICKNAME_BY_ID => r#"SELECT nickname FROM users WHERE id = ?"#, Query::AUTH_NICKNAME_BY_ID => r#"SELECT nickname FROM users WHERE id = ?"#,
Query::AUTH_ANONYMIZE_NOTE_CREATORS => r#"UPDATE notes SET created_by = ? WHERE created_by = ?"#, Query::AUTH_ANONYMIZE_NOTE_CREATORS => r#"UPDATE notes SET created_by = ? WHERE created_by = ?"#,
Query::AUTH_SESSION_EXPIRES_AT => r#"SELECT expires_at FROM user_sessions WHERE token = ?"#, Query::AUTH_SESSION_EXPIRES_AT => r#"SELECT expires_at FROM user_sessions WHERE token = ?"#,
@@ -49,7 +49,7 @@ pub fn get(query: Query) -> &'static str {
Query::AUTH_INSERT_SESSION => r#"INSERT INTO user_sessions (token, user_id, expires_at) VALUES (?, ?, ?)"#, Query::AUTH_INSERT_SESSION => r#"INSERT INTO user_sessions (token, user_id, expires_at) VALUES (?, ?, ?)"#,
Query::AUTH_USER_BY_NICKNAME => r#"SELECT id, nickname, email, password_hash, confirmed_at, is_active FROM users WHERE nickname_key = ?"#, Query::AUTH_USER_BY_NICKNAME => r#"SELECT id, nickname, email, password_hash, confirmed_at, is_active FROM users WHERE nickname_key = ?"#,
Query::AUTH_USER_BY_EMAIL => r#"SELECT id, nickname, email, password_hash, confirmed_at, is_active FROM users WHERE email_key = ?"#, Query::AUTH_USER_BY_EMAIL => r#"SELECT id, nickname, email, password_hash, confirmed_at, is_active FROM users WHERE email_key = ?"#,
Query::AUTH_USER_BY_SHARE_IDENTIFIER => r#"SELECT id, nickname, email, password_hash, confirmed_at, CASE WHEN is_active THEN 1 ELSE 0 END AS is_active FROM users WHERE is_active = 1 AND (email_key = ?1 OR LOWER(external_id) = ?1) LIMIT 1"#, Query::AUTH_USER_BY_SHARE_IDENTIFIER => r#"SELECT id, nickname, email, password_hash, confirmed_at, CASE WHEN is_active THEN 1 ELSE 0 END AS is_active FROM users WHERE is_active = 1 AND (email_key = ?1 OR LOWER(directory_username) = ?1 OR LOWER(external_id) = ?1) LIMIT 1"#,
Query::USER_ATTACH_WORKSPACE => r#"INSERT INTO user_workspaces (user_id, workspace_id) SELECT ?, id FROM workspaces WHERE slug = ?"#, Query::USER_ATTACH_WORKSPACE => r#"INSERT INTO user_workspaces (user_id, workspace_id) SELECT ?, id FROM workspaces WHERE slug = ?"#,
Query::USER_ATTACH_PAD => r#"INSERT INTO user_pads (user_id, pad_id) SELECT ?, id FROM pads WHERE slug = ?"#, Query::USER_ATTACH_PAD => r#"INSERT INTO user_pads (user_id, pad_id) SELECT ?, id FROM pads WHERE slug = ?"#,
Query::USER_LIST_WORKSPACES => r#"SELECT w.slug, w.title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS protected, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END AS private, 1 AS owned, 'rw' AS permission, '' AS shared_by FROM user_workspaces uw JOIN workspaces w ON w.id = uw.workspace_id WHERE uw.user_id = ? UNION SELECT w.slug, w.title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END, 0, rp.permission, COALESCE((SELECT u.nickname FROM user_workspaces owner_uw JOIN users u ON u.id = owner_uw.user_id WHERE owner_uw.workspace_id = w.id LIMIT 1), 'Unknown user') AS shared_by FROM resource_permissions rp JOIN workspaces w ON w.slug = rp.resource_slug WHERE rp.resource_kind = 'workspace' AND rp.user_id = ? ORDER BY updated_at DESC"#, Query::USER_LIST_WORKSPACES => r#"SELECT w.slug, w.title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END AS protected, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END AS private, 1 AS owned, 'rw' AS permission, '' AS shared_by FROM user_workspaces uw JOIN workspaces w ON w.id = uw.workspace_id WHERE uw.user_id = ? UNION SELECT w.slug, w.title, CASE WHEN w.password_hash IS NULL THEN 0 ELSE 1 END, w.updated_at, CASE WHEN w.is_private THEN 1 ELSE 0 END, 0, rp.permission, COALESCE((SELECT u.nickname FROM user_workspaces owner_uw JOIN users u ON u.id = owner_uw.user_id WHERE owner_uw.workspace_id = w.id LIMIT 1), 'Unknown user') AS shared_by FROM resource_permissions rp JOIN workspaces w ON w.slug = rp.resource_slug WHERE rp.resource_kind = 'workspace' AND rp.user_id = ? ORDER BY updated_at DESC"#,