Add tests for count=false and count=only
This commit is contained in:
@@ -471,5 +471,140 @@ mod tests {
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/compat-sessions?count=false")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "compat-session",
|
||||
"id": "01FSHNB530AAPR7PEV8KNBZD5Y",
|
||||
"attributes": {
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"device_id": "LoieH5Iecx",
|
||||
"user_session_id": null,
|
||||
"redirect_uri": null,
|
||||
"created_at": "2022-01-16T14:41:00Z",
|
||||
"user_agent": null,
|
||||
"last_active_at": null,
|
||||
"last_active_ip": null,
|
||||
"finished_at": null,
|
||||
"human_name": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "compat-session",
|
||||
"id": "01FSHNCZP0PPF7X0EVMJNECPZW",
|
||||
"attributes": {
|
||||
"user_id": "01FSHNB530AJ6AC5HQ9X6H4RP4",
|
||||
"device_id": "ZXyvelQWW9",
|
||||
"user_session_id": null,
|
||||
"redirect_uri": null,
|
||||
"created_at": "2022-01-16T14:42:00Z",
|
||||
"user_agent": null,
|
||||
"last_active_at": null,
|
||||
"last_active_ip": null,
|
||||
"finished_at": "2022-01-16T14:43:00Z",
|
||||
"human_name": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNCZP0PPF7X0EVMJNECPZW"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/compat-sessions?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/compat-sessions?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/compat-sessions?count=only")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions?count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=false with filtering
|
||||
let request = Request::get(format!(
|
||||
"/api/admin/v1/compat-sessions?count=false&filter[user]={}",
|
||||
alice.id
|
||||
))
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "compat-session",
|
||||
"id": "01FSHNB530AAPR7PEV8KNBZD5Y",
|
||||
"attributes": {
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"device_id": "LoieH5Iecx",
|
||||
"user_session_id": null,
|
||||
"redirect_uri": null,
|
||||
"created_at": "2022-01-16T14:41:00Z",
|
||||
"user_agent": null,
|
||||
"last_active_at": null,
|
||||
"last_active_ip": null,
|
||||
"finished_at": null,
|
||||
"human_name": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/compat-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/compat-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only with filtering
|
||||
let request =
|
||||
Request::get("/api/admin/v1/compat-sessions?count=only&filter[status]=active")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions?filter[status]=active&count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,5 +381,61 @@ mod tests {
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/oauth2-sessions?count=false")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "oauth2-session",
|
||||
"id": "01FSHN9AG0MKGTBNZ16RDR3PVY",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"finished_at": null,
|
||||
"user_id": null,
|
||||
"user_session_id": null,
|
||||
"client_id": "01FSHN9AG0FAQ50MT1E9FFRPZR",
|
||||
"scope": "urn:mas:admin",
|
||||
"user_agent": null,
|
||||
"last_active_at": null,
|
||||
"last_active_ip": null,
|
||||
"human_name": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions/01FSHN9AG0MKGTBNZ16RDR3PVY"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/oauth2-sessions?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/oauth2-sessions?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/oauth2-sessions?count=only")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions?count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,5 +517,155 @@ mod tests {
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/upstream-oauth-links?count=false")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "upstream-oauth-link",
|
||||
"id": "01FSHN9AG0AQZQP8DX40GD59PW",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"provider_id": "01FSHN9AG09NMZYX8MFYH578R9",
|
||||
"subject": "subject1",
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"human_account_name": "alice@acme"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "upstream-oauth-link",
|
||||
"id": "01FSHN9AG0PJZ6DZNTAA1XKPT4",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"provider_id": "01FSHN9AG09NMZYX8MFYH578R9",
|
||||
"subject": "subject3",
|
||||
"user_id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4",
|
||||
"human_account_name": "bob@acme"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "upstream-oauth-link",
|
||||
"id": "01FSHN9AG0QHEHKX2JNQ2A2D07",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"provider_id": "01FSHN9AG0KEPHYQQXW9XPTX6Z",
|
||||
"subject": "subject2",
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"human_account_name": "alice@example"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/upstream-oauth-links?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/upstream-oauth-links?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/upstream-oauth-links?count=only")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"meta": {
|
||||
"count": 3
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links?count=only"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=false with filtering
|
||||
let request = Request::get(format!(
|
||||
"/api/admin/v1/upstream-oauth-links?count=false&filter[user]={}",
|
||||
alice.id
|
||||
))
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "upstream-oauth-link",
|
||||
"id": "01FSHN9AG0AQZQP8DX40GD59PW",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"provider_id": "01FSHN9AG09NMZYX8MFYH578R9",
|
||||
"subject": "subject1",
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"human_account_name": "alice@acme"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "upstream-oauth-link",
|
||||
"id": "01FSHN9AG0QHEHKX2JNQ2A2D07",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"provider_id": "01FSHN9AG0KEPHYQQXW9XPTX6Z",
|
||||
"subject": "subject2",
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"human_account_name": "alice@example"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only with filtering
|
||||
let request = Request::get(format!(
|
||||
"/api/admin/v1/upstream-oauth-links?count=only&filter[provider]={}",
|
||||
provider1.id
|
||||
))
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links?filter[provider]=01FSHN9AG09NMZYX8MFYH578R9&count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,4 +565,162 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_count_parameter(pool: PgPool) {
|
||||
setup();
|
||||
let mut state = TestState::from_pool(pool).await.unwrap();
|
||||
let admin_token = state.token_with_scope("urn:mas:admin").await;
|
||||
create_test_providers(&mut state).await;
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/upstream-oauth-providers?count=false")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json::<serde_json::Value>();
|
||||
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "upstream-oauth-provider",
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"issuer": "https://appleid.apple.com",
|
||||
"human_name": "Apple ID",
|
||||
"brand_name": "apple",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"disabled_at": "2022-01-16T14:40:00Z"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "upstream-oauth-provider",
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"issuer": "https://login.microsoftonline.com/common/v2.0",
|
||||
"human_name": "Microsoft",
|
||||
"brand_name": "microsoft",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"disabled_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "upstream-oauth-provider",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"issuer": "https://accounts.google.com",
|
||||
"human_name": "Google",
|
||||
"brand_name": "google",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"disabled_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/upstream-oauth-providers?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/upstream-oauth-providers?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/upstream-oauth-providers?count=only")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json::<serde_json::Value>();
|
||||
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 3
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers?count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=false with filtering
|
||||
let request =
|
||||
Request::get("/api/admin/v1/upstream-oauth-providers?count=false&filter[enabled]=true")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json::<serde_json::Value>();
|
||||
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "upstream-oauth-provider",
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"issuer": "https://login.microsoftonline.com/common/v2.0",
|
||||
"human_name": "Microsoft",
|
||||
"brand_name": "microsoft",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"disabled_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "upstream-oauth-provider",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"issuer": "https://accounts.google.com",
|
||||
"human_name": "Google",
|
||||
"brand_name": "google",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"disabled_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only with filtering
|
||||
let request =
|
||||
Request::get("/api/admin/v1/upstream-oauth-providers?count=only&filter[enabled]=false")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json::<serde_json::Value>();
|
||||
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers?count=only&filter[enabled]=false"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,5 +335,121 @@ mod tests {
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/user-emails?count=false")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user-email",
|
||||
"id": "01FSHN9AG09NMZYX8MFYH578R9",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"email": "alice@example.com"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user-email",
|
||||
"id": "01FSHN9AG0KEPHYQQXW9XPTX6Z",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"user_id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4",
|
||||
"email": "bob@example.com"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG0KEPHYQQXW9XPTX6Z"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/user-emails?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/user-emails?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/user-emails?count=only")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails?count=only"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=false with filtering
|
||||
let request = Request::get(format!(
|
||||
"/api/admin/v1/user-emails?count=false&filter[user]={}",
|
||||
alice.id
|
||||
))
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user-email",
|
||||
"id": "01FSHN9AG09NMZYX8MFYH578R9",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"email": "alice@example.com"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only with filtering
|
||||
let request = Request::get(format!(
|
||||
"/api/admin/v1/user-emails?count=only&filter[user]={}",
|
||||
alice.id
|
||||
))
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1186,4 +1186,207 @@ mod tests {
|
||||
.contains("Invalid filter parameters")
|
||||
);
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_count_parameter(pool: PgPool) {
|
||||
setup();
|
||||
let mut state = TestState::from_pool(pool).await.unwrap();
|
||||
let admin_token = state.token_with_scope("urn:mas:admin").await;
|
||||
create_test_tokens(&mut state).await;
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/user-registration-tokens?count=false")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG064K8BYZXSY5G511Z",
|
||||
"attributes": {
|
||||
"token": "token_expired",
|
||||
"valid": false,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"last_used_at": null,
|
||||
"expires_at": "2022-01-15T14:40:00Z",
|
||||
"revoked_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"last_used_at": "2022-01-16T14:40:00Z",
|
||||
"expires_at": null,
|
||||
"revoked_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"token": "token_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"last_used_at": null,
|
||||
"expires_at": null,
|
||||
"revoked_at": "2022-01-16T14:40:00Z"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"last_used_at": null,
|
||||
"expires_at": null,
|
||||
"revoked_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"last_used_at": "2022-01-16T14:40:00Z",
|
||||
"expires_at": null,
|
||||
"revoked_at": "2022-01-16T14:40:00Z"
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/user-registration-tokens?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/user-registration-tokens?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/user-registration-tokens?count=only")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 5
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens?count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=false with filtering
|
||||
let request =
|
||||
Request::get("/api/admin/v1/user-registration-tokens?count=false&filter[valid]=true")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"last_used_at": "2022-01-16T14:40:00Z",
|
||||
"expires_at": null,
|
||||
"revoked_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"last_used_at": null,
|
||||
"expires_at": null,
|
||||
"revoked_at": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens?filter[valid]=true&count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/user-registration-tokens?filter[valid]=true&count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/user-registration-tokens?filter[valid]=true&count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only with filtering
|
||||
let request =
|
||||
Request::get("/api/admin/v1/user-registration-tokens?count=only&filter[revoked]=true")
|
||||
.bearer(&admin_token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens?filter[revoked]=true&count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,5 +416,127 @@ mod tests {
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/user-sessions?count=false")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user-session",
|
||||
"id": "01FSHNB5309NMZYX8MFYH578R9",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:41:00Z",
|
||||
"finished_at": null,
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"user_agent": null,
|
||||
"last_active_at": null,
|
||||
"last_active_ip": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user-session",
|
||||
"id": "01FSHNB530KEPHYQQXW9XPTX6Z",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:41:00Z",
|
||||
"finished_at": "2022-01-16T14:42:00Z",
|
||||
"user_id": "01FSHNB530AJ6AC5HQ9X6H4RP4",
|
||||
"user_agent": null,
|
||||
"last_active_at": null,
|
||||
"last_active_ip": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB530KEPHYQQXW9XPTX6Z"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/user-sessions?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/user-sessions?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/user-sessions?count=only")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions?count=only"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=false with filtering
|
||||
let request = Request::get(format!(
|
||||
"/api/admin/v1/user-sessions?count=false&filter[user]={}",
|
||||
alice.id
|
||||
))
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user-session",
|
||||
"id": "01FSHNB5309NMZYX8MFYH578R9",
|
||||
"attributes": {
|
||||
"created_at": "2022-01-16T14:41:00Z",
|
||||
"finished_at": null,
|
||||
"user_id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"user_agent": null,
|
||||
"last_active_at": null,
|
||||
"last_active_ip": null
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only with filtering
|
||||
let request = Request::get("/api/admin/v1/user-sessions?count=only&filter[status]=active")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions?filter[status]=active&count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,3 +204,200 @@ pub async fn handler(
|
||||
|
||||
Ok(Json(response))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hyper::{Request, StatusCode};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup};
|
||||
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
async fn test_list_users(pool: PgPool) {
|
||||
setup();
|
||||
let mut state = TestState::from_pool(pool).await.unwrap();
|
||||
let token = state.token_with_scope("urn:mas:admin").await;
|
||||
let mut rng = state.rng();
|
||||
|
||||
// Provision two users
|
||||
let mut repo = state.repository().await.unwrap();
|
||||
repo.user()
|
||||
.add(&mut rng, &state.clock, "alice".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
repo.user()
|
||||
.add(&mut rng, &state.clock, "bob".to_owned())
|
||||
.await
|
||||
.unwrap();
|
||||
repo.save().await.unwrap();
|
||||
|
||||
// Test default behavior (count=true)
|
||||
let request = Request::get("/api/admin/v1/users").bearer(&token).empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
},
|
||||
"data": [
|
||||
{
|
||||
"type": "user",
|
||||
"id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4",
|
||||
"attributes": {
|
||||
"username": "bob",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"locked_at": null,
|
||||
"deactivated_at": null,
|
||||
"admin": false,
|
||||
"legacy_guest": false
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0AJ6AC5HQ9X6H4RP4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"username": "alice",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"locked_at": null,
|
||||
"deactivated_at": null,
|
||||
"admin": false,
|
||||
"legacy_guest": false
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users?page[first]=10",
|
||||
"first": "/api/admin/v1/users?page[first]=10",
|
||||
"last": "/api/admin/v1/users?page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/users?count=false")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user",
|
||||
"id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4",
|
||||
"attributes": {
|
||||
"username": "bob",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"locked_at": null,
|
||||
"deactivated_at": null,
|
||||
"admin": false,
|
||||
"legacy_guest": false
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0AJ6AC5HQ9X6H4RP4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "user",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"username": "alice",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"locked_at": null,
|
||||
"deactivated_at": null,
|
||||
"admin": false,
|
||||
"legacy_guest": false
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users?count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/users?count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/users?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/users?count=only")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users?count=only"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
|
||||
// Test count=false with filtering
|
||||
let request = Request::get("/api/admin/v1/users?count=false&filter[search]=alice")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "user",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"username": "alice",
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
"locked_at": null,
|
||||
"deactivated_at": null,
|
||||
"admin": false,
|
||||
"legacy_guest": false
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users?filter[search]=alice&count=false&page[first]=10",
|
||||
"first": "/api/admin/v1/users?filter[search]=alice&count=false&page[first]=10",
|
||||
"last": "/api/admin/v1/users?filter[search]=alice&count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
|
||||
// Test count=only with filtering
|
||||
let request = Request::get("/api/admin/v1/users?count=only&filter[search]=alice")
|
||||
.bearer(&token)
|
||||
.empty();
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users?filter[search]=alice&count=only"
|
||||
}
|
||||
}
|
||||
"#);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user