Skip to content

Commit 05899c0

Browse files
authored
feat: Realm helper with required and optional parameters separated (#164)
* added realm helper with required and optional parameters separated * bump Rust requirement to 1.88 * lower Rust requirement to 1.87 * added integration example and corrected field visibility * added comments * updated release automation script, split into smaller modules * fixed resource modules visibility * added builder implementation * cleanup empty modules * align core and resource add user examples * removed not needed permission from release automation * split generation into submethods * full comments on root methods * remove builder and resource from default features, add group feature to activate both * update docs * do not run doctests with default features
1 parent 1752765 commit 05899c0

35 files changed

+17527
-240
lines changed

.github/workflows/integration.yml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,23 @@ jobs:
1515

1616
steps:
1717
- uses: actions/checkout@v4
18-
- uses: dtolnay/rust-toolchain@1.84.0
18+
- uses: dtolnay/rust-toolchain@1.87.0
1919
- run: mkdir .cargo && cp .cargo-config.toml .cargo/config.toml
20-
- name: Build
20+
- name: Build with default features
2121
run: cargo build
22-
- name: Run unit tests
23-
run: cargo test
24-
- name: Build with features
25-
run: cargo build --features=rc,schemars
26-
- name: Run unit tests with features
27-
run: cargo test --features=rc,schemars
22+
- name: Run unit tests with default features
23+
run: cargo test --lib
24+
- name: Build with all top level features
25+
run: cargo build --features=rc,schemars,multipart,resource-builder
26+
- name: Run unit tests with all top level features
27+
run: cargo test --features=rc,schemars,multipart,resource-builder
2828
- name: Run integration tests
2929
run: |
3030
export KEYCLOAK_VERSION=`cargo metadata --no-deps --format-version 1 | jq '.packages[0].version | split(".") | map(tonumber) | .[:-1] + [.[2] / 100] | map(floor) | join(".")' | tr -d '"'`
3131
docker run -p 8080:8080 --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password -e KC_FEATURES=admin-api quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} start-dev &
3232
sleep 40
3333
cargo run --example=adduser
34+
cargo run --example=resource_adduser --features=resource-builder
3435
cargo run --example=importconfig --features=multipart
35-
cargo run --example=adduser --features=rc,schemars,multipart
36+
cargo run --example=adduser --features=rc,schemars,multipart,resource-builder
37+
cargo run --example=resource_adduser --features=rc,schemars,multipart,resource-builder

Cargo.toml

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,39 +11,19 @@ homepage = "https://github.com/kilork/keycloak"
1111
keywords = ["api", "async", "keycloak", "rest"]
1212
license = "Unlicense OR MIT"
1313
repository = "https://github.com/kilork/keycloak"
14-
rust-version = "1.84"
14+
rust-version = "1.87"
1515

1616
[features]
1717
default = ["tags-all"]
18+
resource-builder = ["builder", "resource"]
1819
schemars = ["dep:schemars"]
1920
multipart = ["reqwest/multipart"]
2021
rc = ["rc-map", "rc-str", "rc-val", "rc-vec"]
2122
rc-map = ["serde/rc"]
2223
rc-str = ["serde/rc"]
2324
rc-val = ["serde/rc"]
2425
rc-vec = ["serde/rc"]
25-
tags-all = [
26-
"tag-attack-detection",
27-
"tag-authentication-management",
28-
"tag-client-attribute-certificate",
29-
"tag-client-initial-access",
30-
"tag-client-registration-policy",
31-
"tag-client-role-mappings",
32-
"tag-client-scopes",
33-
"tag-clients",
34-
"tag-component",
35-
"tag-groups",
36-
"tag-identity-providers",
37-
"tag-key",
38-
"tag-organizations",
39-
"tag-protocol-mappers",
40-
"tag-realms-admin",
41-
"tag-role-mapper",
42-
"tag-roles",
43-
"tag-roles-by-id",
44-
"tag-scope-mappings",
45-
"tag-users",
46-
]
26+
tags-all = ["tag-attack-detection", "tag-authentication-management", "tag-client-attribute-certificate", "tag-client-initial-access", "tag-client-registration-policy", "tag-client-role-mappings", "tag-client-scopes", "tag-clients", "tag-component", "tag-groups", "tag-identity-providers", "tag-key", "tag-organizations", "tag-protocol-mappers", "tag-realms-admin", "tag-role-mapper", "tag-roles", "tag-roles-by-id", "tag-scope-mappings", "tag-users", "tag-none"]
4727
tag-attack-detection = []
4828
tag-authentication-management = []
4929
tag-client-attribute-certificate = []
@@ -64,6 +44,9 @@ tag-roles = []
6444
tag-roles-by-id = []
6545
tag-scope-mappings = []
6646
tag-users = []
47+
tag-none = []
48+
resource = []
49+
builder = []
6750

6851
[dependencies]
6952
reqwest = { version = "0.12", default-features = false, features = ["json"] }
@@ -79,7 +62,7 @@ percent-encoding = "2.3.1"
7962
[dev-dependencies]
8063
tokio = { version = "1", features = ["full"] }
8164
heck = "0.5"
82-
clap = { version = "4", features = ["derive", "std"], default-features = false }
65+
clap = { version = "4", features = ["derive", "help", "std"], default-features = false }
8366
toml = "0.8"
8467
serde = { version = "1", features = ["derive", "rc"] }
8568
indexmap = { version = "2", features = ["serde"] }

README.md

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ Default flags: `tags-all`.
1616
- `schemars`: add [schemars](https://crates.io/crates/schemars) support.
1717
- `multipart`: add multipart support to reqwest, enabling extra methods in API.
1818
- `tags-all`: activate all tags (resource groups) in REST API, it is default behavior. Disable default features and use individual `tag-xxx` features to activate only required resource groups. For a full list reference the [Cargo.toml](Cargo.toml).
19+
- `resource-builder`: add resource builder support.
1920

2021
## Usage
2122

22-
Requires Rust version >= `1.84.0`.
23+
Requires Rust version >= `1.87.0`.
2324

2425
Add dependency to Cargo.toml:
2526

@@ -29,51 +30,44 @@ keycloak = "~26.3"
2930
```
3031

3132
```rust
32-
use keycloak::{
33-
types::*,
34-
{KeycloakAdmin, KeycloakAdminToken},
35-
};
36-
3733
#[tokio::main]
3834
async fn main() -> Result<(), Box<dyn std::error::Error>> {
35+
use keycloak::{types::*, KeycloakAdmin, KeycloakAdminToken};
36+
37+
const REALM: &str = "resource";
38+
3939
let url = std::env::var("KEYCLOAK_ADDR").unwrap_or_else(|_| "http://localhost:8080".into());
4040
let user = std::env::var("KEYCLOAK_USER").unwrap_or_else(|_| "admin".into());
4141
let password = std::env::var("KEYCLOAK_PASSWORD").unwrap_or_else(|_| "password".into());
4242

4343
let client = reqwest::Client::new();
4444
let admin_token = KeycloakAdminToken::acquire(&url, &user, &password, &client).await?;
4545

46-
eprintln!("{:?}", admin_token);
46+
eprintln!("{admin_token:?}");
4747

4848
let admin = KeycloakAdmin::new(&url, admin_token, client);
4949

5050
admin
5151
.post(RealmRepresentation {
52-
realm: Some("test".into()),
52+
realm: Some(REALM.into()),
5353
..Default::default()
5454
})
5555
.await?;
5656

57-
let response = admin
58-
.realm_users_post(
59-
"test",
60-
UserRepresentation {
61-
username: Some("user".into()),
62-
..Default::default()
63-
},
64-
)
57+
let realm = admin.realm(REALM);
58+
59+
let response = realm
60+
.users_post(UserRepresentation {
61+
username: Some("user".into()),
62+
..Default::default()
63+
})
6564
.await?;
6665

6766
eprintln!("{:?}", response.to_id());
6867

69-
let users = admin
70-
.realm_users_get(
71-
"test", None, None, None, None, None, None, None, None, None, None, None, None, None,
72-
None,
73-
)
74-
.await?;
68+
let users = realm.users_get().username("user".to_string()).await?;
7569

76-
eprintln!("{:?}", users);
70+
eprintln!("{users:?}");
7771

7872
let id = users
7973
.iter()
@@ -84,12 +78,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
8478
.unwrap()
8579
.to_string();
8680

87-
admin
88-
.realm_users_with_user_id_delete("test", id.as_str())
89-
.await?;
90-
91-
admin.realm_delete("test").await?;
81+
realm.users_with_user_id_delete(id.as_str()).await?;
9282

83+
realm.delete().await?;
9384
Ok(())
9485
}
9586
```
@@ -106,5 +97,5 @@ Example: official version `13.0.1` is `13.0.100` for crate version. `13.0.102` m
10697
To update current version use provided [update.ts](./update.ts) `deno` script:
10798

10899
```sh
109-
deno run --allow-env=KEYCLOAK_RUST_VERSION,KEYCLOAK_VERSION,KEYCLOAK_RUST_MAJOR_VERSION --allow-read=Cargo.toml --allow-write=Cargo.toml,api/openapi.json,src/types.rs,src/rest/generated_rest.rs --allow-net=keycloak.org,www.keycloak.org --allow-run=cargo,gh,git,handlebars-magic update.ts
100+
deno run --allow-env=KEYCLOAK_RUST_VERSION,KEYCLOAK_VERSION,KEYCLOAK_RUST_MAJOR_VERSION --allow-read=Cargo.toml --allow-write=Cargo.toml,api/openapi.json,src/types.rs,src/rest/generated_rest.rs,src/resource --allow-net=keycloak.org,www.keycloak.org --allow-run=cargo,gh,git,handlebars-magic update.ts
110101
```

examples/adduser.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
1-
use keycloak::{
2-
types::*,
3-
{KeycloakAdmin, KeycloakAdminToken},
4-
};
5-
61
#[tokio::main]
72
async fn main() -> Result<(), Box<dyn std::error::Error>> {
3+
use keycloak::{
4+
types::*,
5+
{KeycloakAdmin, KeycloakAdminToken},
6+
};
7+
8+
const REALM: &str = "test";
9+
810
let url = std::env::var("KEYCLOAK_ADDR").unwrap_or_else(|_| "http://localhost:8080".into());
911
let user = std::env::var("KEYCLOAK_USER").unwrap_or_else(|_| "admin".into());
1012
let password = std::env::var("KEYCLOAK_PASSWORD").unwrap_or_else(|_| "password".into());
1113

1214
let client = reqwest::Client::new();
1315
let admin_token = KeycloakAdminToken::acquire(&url, &user, &password, &client).await?;
1416

15-
eprintln!("{:?}", admin_token);
17+
eprintln!("{admin_token:?}");
1618

1719
let admin = KeycloakAdmin::new(&url, admin_token, client);
1820

1921
admin
2022
.post(RealmRepresentation {
21-
realm: Some("test".into()),
23+
realm: Some(REALM.into()),
2224
..Default::default()
2325
})
2426
.await?;
2527

2628
let response = admin
2729
.realm_users_post(
28-
"test",
30+
REALM,
2931
UserRepresentation {
3032
username: Some("user".into()),
3133
..Default::default()
@@ -37,12 +39,25 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3739

3840
let users = admin
3941
.realm_users_get(
40-
"test", None, None, None, None, None, None, None, None, None, None, None, None, None,
42+
REALM,
43+
None,
44+
None,
45+
None,
46+
None,
47+
None,
48+
None,
49+
None,
50+
None,
51+
None,
52+
None,
53+
None,
54+
None,
4155
None,
56+
Some("user".into()),
4257
)
4358
.await?;
4459

45-
eprintln!("{:?}", users);
60+
eprintln!("{users:?}");
4661

4762
let id = users
4863
.iter()
@@ -54,10 +69,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
5469
.to_string();
5570

5671
admin
57-
.realm_users_with_user_id_delete("test", id.as_str())
72+
.realm_users_with_user_id_delete(REALM, id.as_str())
5873
.await?;
5974

60-
admin.realm_delete("test").await?;
75+
admin.realm_delete(REALM).await?;
6176

6277
Ok(())
6378
}

0 commit comments

Comments
 (0)