pub async fn ban(
    session_id: &str,
    delete_all: bool,
    user: &User,
    room: &Room,
) -> Result<Response, Rejection> {
    if !is_session_id(&session_id) {
        warn!("Ignoring ban request: invalid session_id.");
        return Err(Error::ValidationFailed.into());
    }

    let mut auth = AuthorizationRequired { moderator: true, ..Default::default() };

    let mut conn = storage::get_conn()?;
    let tx = storage::get_transaction(&mut conn)?;

    tx.prepare_cached("INSERT OR IGNORE INTO users (session_id) VALUES (?)")
        .map_err(db_error)?
        .execute(params![session_id])
        .map_err(db_error)?;

    let userid: i64;

    match tx
        .prepare_cached(
            "SELECT user, moderator, global_moderator FROM user_permissions \
            WHERE room = ? AND session_id = ?",
        )
        .map_err(db_error)?
        .query_row(params![room.id, session_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)))
    {
        Ok((uid, is_mod, is_global_mod)) => {
            if is_global_mod {
                warn!("Cannot ban {} from {}: user is a global moderator", session_id, room.token);
                return Err(Error::Unauthorized.into());
            }
            userid = uid;
            if is_mod {
                // To ban a moderator we have to be a room admin, not just a moderator.
                auth.admin = true;
            }
        }
        Err(rusqlite::Error::QueryReturnedNoRows) => {
            let response = json!({"status_code": StatusCode::NOT_FOUND.as_u16()});
            return Ok(warp::reply::json(&response).into_response());
        }
        Err(_) => return Err(Error::DatabaseFailedInternally.into()),
    };

    require_authorization(&tx, user, room, auth)?;

    if let Err(e) = tx
        .prepare_cached(
            "\
            INSERT INTO user_permission_overrides (room, user, banned, moderator, admin) \
            VALUES (?, ?, TRUE, FALSE, FALSE) \
            ON CONFLICT DO UPDATE SET banned = TRUE, moderator = FALSE, admin = FALSE
            ",
        )
        .map_err(db_error)?
        .execute(params![room.id, userid])
    {
        error!("Failed to insert ban for {} in {}: {}", session_id, room.token, e);
        return Err(Error::DatabaseFailedInternally.into());
    }

    let mut posts_removed = 0;
    let mut files_removed = 0;
    if delete_all {
        posts_removed += match tx
            .prepare_cached(
                "UPDATE messages SET data = NULL, data_size = NULL, signature = NULL \
                WHERE room = ? AND user = ?",
            )
            .map_err(db_error)?
            .execute(params![room.id, userid])
        {
            Ok(count) => count,
            Err(e) => {
                error!("Failed to delete posts by {} from {}: {}", session_id, room.token, e);
                return Err(Error::DatabaseFailedInternally.into());
            }
        };

        // We don't actually delete from disk right now, but clear the room (so that they aren't
        // retrievable) and set them to be expired (so that the next file pruning will delete them
        // from disk).
        files_removed = tx
            .prepare_cached(
                "UPDATE files SET room = NULL, expiry = ? WHERE room = ? AND uploader = ?",
            )
            .map_err(db_error)?
            .execute(params![unixtime_f64(), room.id, userid])
            .map_err(db_error)?;
    }

    if let Err(e) = tx.commit() {
        info!("Failed to ban/delete user {} from {}: {}", session_id, room.token, e);
        return Err(Error::DatabaseFailedInternally.into());
    }

    info!(
        "Banned {} from room {}: {} messages and {} files deleted",
        session_id, room.token, posts_removed, files_removed
    );

    Ok(warp::reply::json(&models::StatusCode { status_code: StatusCode::OK.as_u16() })
        .into_response())
}
/// Bans the given `public_key`, optionally also deleting all the user's messages and uploaded
/// files.  Requires a moderator for a regular user, and admin for a moderator/admin.
Bans the given `public_key`, optionally also deleting all the user's messages and uploaded
files.  Requires a moderator for a regular user, and admin for a moderator/admin.
Bans the given ` public_key ` optionally also deleting all the user ' s messages and uploaded files . Requires a moderator for a regular user and admin for a moderator / admin .
pub async fn ban(
    session_id: &str,
    delete_all: bool,
    user: &User,
    room: &Room,
) -> Result<Response, Rejection> {
    if !is_session_id(&session_id) {
        warn!("Ignoring ban request: invalid session_id.");
        return Err(Error::ValidationFailed.into());
    }
    let mut auth = AuthorizationRequired { moderator: true, ..Default::default() };
    let mut conn = storage::get_conn()?;
    let tx = storage::get_transaction(&mut conn)?;
    tx.prepare_cached("INSERT OR IGNORE INTO users (session_id) VALUES (?)")
        .map_err(db_error)?
        .execute(params![session_id])
        .map_err(db_error)?;
    let userid: i64;
    match tx
        .prepare_cached(
            "SELECT user, moderator, global_moderator FROM user_permissions \
            WHERE room = ? AND session_id = ?",
        )
        .map_err(db_error)?
        .query_row(params![room.id, session_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)))
    {
        Ok((uid, is_mod, is_global_mod)) => {
            if is_global_mod {
                warn!("Cannot ban {} from {}: user is a global moderator", session_id, room.token);
                return Err(Error::Unauthorized.into());
            }
            userid = uid;
            if is_mod {
                // To ban a moderator we have to be a room admin, not just a moderator.
                auth.admin = true;
            }
        }
        Err(rusqlite::Error::QueryReturnedNoRows) => {
            let response = json!({"status_code": StatusCode::NOT_FOUND.as_u16()});
            return Ok(warp::reply::json(&response).into_response());
        }
        Err(_) => return Err(Error::DatabaseFailedInternally.into()),
    };
    require_authorization(&tx, user, room, auth)?;
    if let Err(e) = tx
        .prepare_cached(
            "\
            INSERT INTO user_permission_overrides (room, user, banned, moderator, admin) \
            VALUES (?, ?, TRUE, FALSE, FALSE) \
            ON CONFLICT DO UPDATE SET banned = TRUE, moderator = FALSE, admin = FALSE
            ",
        )
        .map_err(db_error)?
        .execute(params![room.id, userid])
    {
        error!("Failed to insert ban for {} in {}: {}", session_id, room.token, e);
        return Err(Error::DatabaseFailedInternally.into());
    }
    let mut posts_removed = 0;
    let mut files_removed = 0;
    if delete_all {
        posts_removed += match tx
            .prepare_cached(
                "UPDATE messages SET data = NULL, data_size = NULL, signature = NULL \
                WHERE room = ? AND user = ?",
            )
            .map_err(db_error)?
            .execute(params![room.id, userid])
        {
            Ok(count) => count,
            Err(e) => {
                error!("Failed to delete posts by {} from {}: {}", session_id, room.token, e);
                return Err(Error::DatabaseFailedInternally.into());
            }
        };
        // We don't actually delete from disk right now, but clear the room (so that they aren't
        // retrievable) and set them to be expired (so that the next file pruning will delete them
        // from disk).
        files_removed = tx
            .prepare_cached(
                "UPDATE files SET room = NULL, expiry = ? WHERE room = ? AND uploader = ?",
            )
            .map_err(db_error)?
            .execute(params![unixtime_f64(), room.id, userid])
            .map_err(db_error)?;
    }
    if let Err(e) = tx.commit() {
        info!("Failed to ban/delete user {} from {}: {}", session_id, room.token, e);
        return Err(Error::DatabaseFailedInternally.into());
    }
    info!(
        "Banned {} from room {}: {} messages and {} files deleted",
        session_id, room.token, posts_removed, files_removed
    );
    Ok(warp::reply::json(&models::StatusCode { status_code: StatusCode::OK.as_u16() })
        .into_response())
}
pub async fn ban ( session_id : & str , delete_all : bool , user : & User , room : & Room , ) -> Result < Response , Rejection > { if ! is_session_id ( & session_id ) { warn ! ( " " ) ; return Err ( Error :: ValidationFailed . into ( ) ) ; } let mut auth = AuthorizationRequired { moderator : true , .. Default :: default ( ) } ; let mut conn = storage :: get_conn ( ) ? ; let tx = storage :: get_transaction ( & mut conn ) ? ; tx . prepare_cached ( " " ) . map_err ( db_error ) ? . execute ( params ! [ session_id ] ) . map_err ( db_error ) ? ; let userid : i64 ; match tx . prepare_cached ( " \
 " , ) . map_err ( db_error ) ? . query_row ( params ! [ room id session_id ] , | row | Ok ( ( row . get ( 0 ) ? , row . get ( 1 ) ? , row . get ( 2 ) ? ) ) ) { Ok ( ( uid , is_mod , is_global_mod ) ) => { if is_global_mod { warn ! ( " " session_id room token ) ; return Err ( Error :: Unauthorized . into ( ) ) ; } userid = uid ; if is_mod { // To ban a moderator we have to be a room admin, not just a moderator. auth . admin = true ; } } Err ( rusqlite :: Error :: QueryReturnedNoRows ) => { let response = json ! ( { " " StatusCode NOT_FOUND as_u16 ( ) } ) ; return Ok ( warp :: reply :: json ( & response ) . into_response ( ) ) ; } Err ( _ ) => return Err ( Error :: DatabaseFailedInternally . into ( ) ) , } ; require_authorization ( & tx , user , room , auth ) ? ; if let Err ( e ) = tx . prepare_cached ( " \
 \
 \
 " , ) . map_err ( db_error ) ? . execute ( params ! [ room id userid ] ) { error ! ( " " session_id room token e ) ; return Err ( Error :: DatabaseFailedInternally . into ( ) ) ; } let mut posts_removed = 0 ; let mut files_removed = 0 ; if delete_all { posts_removed += match tx . prepare_cached ( " \
 " , ) . map_err ( db_error ) ? . execute ( params ! [ room id userid ] ) { Ok ( count ) => count , Err ( e ) => { error ! ( " " session_id room token e ) ; return Err ( Error :: DatabaseFailedInternally . into ( ) ) ; } } ; // We don't actually delete from disk right now, but clear the room (so that they aren't // retrievable) and set them to be expired (so that the next file pruning will delete them // from disk). files_removed = tx . prepare_cached ( " " , ) . map_err ( db_error ) ? . execute ( params ! [ unixtime_f64 ( ) room id userid ] ) . map_err ( db_error ) ? ; } if let Err ( e ) = tx . commit ( ) { info ! ( " " session_id room token e ) ; return Err ( Error :: DatabaseFailedInternally . into ( ) ) ; } info ! ( " " session_id room token posts_removed files_removed ) ; Ok ( warp :: reply :: json ( & models :: StatusCode { status_code : StatusCode :: OK . as_u16 ( ) } ) . into_response ( ) ) }
Bans the given `public_key`, optionally also deleting all the user's messages and uploaded
files.
Bans the given ` public_key ` optionally also deleting all the user ' s messages and uploaded files .
session_id
&str
delete_all
bool
user
&User
room
&Room
session_id
&str
delete_all
bool
user
&User
room
&Room