Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[server] Add admin db user add #856 #868

Merged
merged 1 commit into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions agdb_server/openapi/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,46 @@
]
}
},
"/api/v1/admin/db/user/add": {
"post": {
"tags": [
"crate::routes::admin::db::user"
],
"operationId": "add",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AddDatabaseUser"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "user added"
},
"401": {
"description": "unauthorized"
},
"403": {
"description": "user must be a db admin / cannot add self"
},
"464": {
"description": "user not found"
},
"466": {
"description": "db not found"
}
},
"security": [
{
"Token": []
}
]
}
},
"/api/v1/admin/db/user/list": {
"get": {
"tags": [
Expand Down
1 change: 1 addition & 0 deletions agdb_server/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use utoipa::OpenApi;
crate::routes::status,
crate::routes::admin::db::list,
crate::routes::admin::db::remove,
crate::routes::admin::db::user::add,
crate::routes::admin::db::user::list,
crate::routes::admin::user::change_password,
crate::routes::admin::user::create,
Expand Down
5 changes: 3 additions & 2 deletions agdb_server/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ pub(crate) fn app(config: Config, shutdown_sender: Sender<()>, db_pool: DbPool)
shutdown_sender,
};

let admin_db_user_router_v1 =
Router::new().route("/list", routing::get(routes::admin::db::user::list));
let admin_db_user_router_v1 = Router::new()
.route("/list", routing::get(routes::admin::db::user::list))
.route("/add", routing::post(routes::admin::db::user::add));

let admin_db_router_v1 = Router::new()
.route("/list", routing::get(routes::admin::db::list))
Expand Down
24 changes: 24 additions & 0 deletions agdb_server/src/routes/admin/db/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ use axum::extract::State;
use axum::http::StatusCode;
use axum::Json;

#[utoipa::path(post,
path = "/api/v1/admin/db/user/add",
request_body = AddDatabaseUser,
security(("Token" = [])),
responses(
(status = 201, description = "user added"),
(status = 401, description = "unauthorized"),
(status = 403, description = "user must be a db admin / cannot add self"),
(status = 464, description = "user not found"),
(status = 466, description = "db not found"),
)
)]
pub(crate) async fn add(
_admin: AdminId,
State(db_pool): State<DbPool>,
Json(request): Json<DbUser>,
) -> ServerResponse {
let db = db_pool.find_db_id(&request.database)?;
let db_user = db_pool.find_user_id(&request.user)?;
db_pool.add_db_user(db, db_user, &request.role.to_string())?;

Ok(StatusCode::CREATED)
}

#[utoipa::path(get,
path = "/api/v1/admin/db/user/list",
security(("Token" = [])),
Expand Down
1 change: 1 addition & 0 deletions agdb_server/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub const DB_LIST_URI: &str = "/db/list";
pub const ADMIN_USER_CREATE_URI: &str = "/admin/user/create";
pub const ADMIN_DB_LIST_URI: &str = "/admin/db/list";
pub const ADMIN_DB_REMOVE_URI: &str = "/admin/db/remove";
pub const ADMIN_DB_USER_ADD_URI: &str = "/admin/db/user/add";
pub const ADMIN_DB_USER_LIST_URI: &str = "/admin/db/user/list";
pub const ADMIN_USER_LIST_URI: &str = "/admin/user/list";
pub const ADMIN_CHANGE_PASSWORD_URI: &str = "/admin/user/change_password";
Expand Down
127 changes: 127 additions & 0 deletions agdb_server/tests/routes/admin_db_user_add_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use crate::AddUser;
use crate::Db;
use crate::TestServer;
use crate::ADMIN_DB_USER_ADD_URI;
use crate::DB_LIST_URI;
use crate::NO_TOKEN;

#[tokio::test]
async fn add_db_user() -> anyhow::Result<()> {
let server = TestServer::new().await?;
let user = server.init_user().await?;
let other = server.init_user().await?;
let db = server.init_db("memory", &user).await?;
let role = AddUser {
database: &db,
user: &other.name,
role: "admin",
};
let (_, list) = server.get::<Vec<Db>>(DB_LIST_URI, &other.token).await?;
assert_eq!(list?, vec![]);
assert_eq!(
server
.post(ADMIN_DB_USER_ADD_URI, &role, &server.admin_token)
.await?
.0,
201
);
let (_, list) = server.get::<Vec<Db>>(DB_LIST_URI, &other.token).await?;
let expected = vec![Db {
name: db,
db_type: "memory".to_string(),
}];
assert_eq!(list?, expected);
Ok(())
}

#[tokio::test]
async fn change_user_role() -> anyhow::Result<()> {
let server = TestServer::new().await?;
let user = server.init_user().await?;
let other = server.init_user().await?;
let db = server.init_db("memory", &user).await?;
let mut role = AddUser {
database: &db,
user: &other.name,
role: "write",
};
assert_eq!(
server
.post(ADMIN_DB_USER_ADD_URI, &role, &server.admin_token)
.await?
.0,
201
);
role.role = "admin";
assert_eq!(
server
.post(ADMIN_DB_USER_ADD_URI, &role, &server.admin_token)
.await?
.0,
201
);
role.role = "write";
role.user = &user.name;
assert_eq!(
server
.post(ADMIN_DB_USER_ADD_URI, &role, &server.admin_token)
.await?
.0,
201
);

Ok(())
}

#[tokio::test]
async fn db_not_found() -> anyhow::Result<()> {
let server = TestServer::new().await?;
let role = AddUser {
database: "db_not_found",
user: "some_user",
role: "read",
};
assert_eq!(
server
.post(ADMIN_DB_USER_ADD_URI, &role, &server.admin_token)
.await?
.0,
466
);
Ok(())
}

#[tokio::test]
async fn user_not_found() -> anyhow::Result<()> {
let server = TestServer::new().await?;
let user = server.init_user().await?;
let db = server.init_db("memory", &user).await?;
let role = AddUser {
database: &db,
user: "user_not_found",
role: "read",
};
assert_eq!(
server
.post(ADMIN_DB_USER_ADD_URI, &role, &server.admin_token)
.await?
.0,
464
);
Ok(())
}

#[tokio::test]
async fn no_token() -> anyhow::Result<()> {
let server = TestServer::new().await?;
let role = AddUser {
database: "my_db",
user: "bob",
role: "admin",
};
assert_eq!(
server.post(ADMIN_DB_USER_ADD_URI, &role, NO_TOKEN).await?.0,
401
);
Ok(())
}
1 change: 1 addition & 0 deletions agdb_server/tests/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod admin_db_list_test;
mod admin_db_remove_test;
mod admin_db_user_add_test;
mod admin_db_user_list_test;
mod admin_user_change_password_test;
mod admin_user_create_test;
Expand Down