Merge remote-tracking branch 'origin/main' into quenting/admin-api/optional-count
This commit is contained in:
2
.github/workflows/build.yaml
vendored
2
.github/workflows/build.yaml
vendored
@@ -268,7 +268,7 @@ jobs:
|
||||
mirrors = ["mirror.gcr.io"]
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3.5.0
|
||||
uses: docker/login-action@v3.6.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
|
||||
56
Cargo.lock
generated
56
Cargo.lock
generated
@@ -184,9 +184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.99"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
@@ -553,9 +553,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5"
|
||||
checksum = "98e529aee37b5c8206bb4bf4c44797127566d72f76952c970bd3d1e85de8f4e2"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"bytes",
|
||||
@@ -572,8 +572,7 @@ dependencies = [
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
@@ -587,9 +586,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.5.2"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
|
||||
checksum = "0ac7a6beb1182c7e30253ee75c3e918080bfb83f5a3023bcdf7209d85fd147e6"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -598,7 +597,6 @@ dependencies = [
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -607,9 +605,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum-extra"
|
||||
version = "0.10.1"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d"
|
||||
checksum = "d86d701cd16f401888ebe9c3214dc838c7ef27a405d5726196765a913603b5dd"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-core",
|
||||
@@ -623,10 +621,10 @@ dependencies = [
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"tower",
|
||||
"serde_core",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -822,9 +820,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1de8bc0aa9e9385ceb3bf0c152e3a9b9544f6c4a912c8ae504e80c1f0368603"
|
||||
checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
@@ -971,9 +969,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.47"
|
||||
version = "4.5.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931"
|
||||
checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -981,9 +979,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.47"
|
||||
version = "4.5.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6"
|
||||
checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -4679,9 +4677,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "psl"
|
||||
version = "2.1.141"
|
||||
version = "2.1.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98c10a4dce9ad24c1fad826cffc79a624cf626bfaddb466e969368a53d877b30"
|
||||
checksum = "f9bc7bed4cdf5168c58514ad64f37615f6683882209e2b6ba345cda0c6b8d949"
|
||||
dependencies = [
|
||||
"psl-types",
|
||||
]
|
||||
@@ -5511,9 +5509,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.225"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
@@ -5521,18 +5519,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.225"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.225"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6347,9 +6345,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.3"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd"
|
||||
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -88,7 +88,7 @@ version = "0.1.89"
|
||||
|
||||
# High-level error handling
|
||||
[workspace.dependencies.anyhow]
|
||||
version = "1.0.99"
|
||||
version = "1.0.100"
|
||||
|
||||
# Assert that a value matches a pattern
|
||||
[workspace.dependencies.assert_matches]
|
||||
@@ -96,11 +96,11 @@ version = "1.5.0"
|
||||
|
||||
# HTTP router
|
||||
[workspace.dependencies.axum]
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
|
||||
# Extra utilities for Axum
|
||||
[workspace.dependencies.axum-extra]
|
||||
version = "0.10.1"
|
||||
version = "0.10.2"
|
||||
features = ["cookie-private", "cookie-key-expansion", "typed-header"]
|
||||
|
||||
# Axum macros
|
||||
@@ -137,7 +137,7 @@ version = "1.10.1"
|
||||
|
||||
# UTF-8 paths
|
||||
[workspace.dependencies.camino]
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
features = ["serde1"]
|
||||
|
||||
# ChaCha20Poly1305 AEAD
|
||||
@@ -167,7 +167,7 @@ features = ["serde", "clock"]
|
||||
|
||||
# CLI argument parsing
|
||||
[workspace.dependencies.clap]
|
||||
version = "4.5.47"
|
||||
version = "4.5.48"
|
||||
features = ["derive"]
|
||||
|
||||
# Object Identifiers (OIDs) as constants
|
||||
@@ -476,7 +476,7 @@ features = ["std", "pkcs5", "encryption"]
|
||||
|
||||
# Public Suffix List
|
||||
[workspace.dependencies.psl]
|
||||
version = "2.1.141"
|
||||
version = "2.1.145"
|
||||
|
||||
# High-precision clock
|
||||
[workspace.dependencies.quanta]
|
||||
@@ -582,7 +582,7 @@ version = "0.42.0"
|
||||
|
||||
# Serialization and deserialization
|
||||
[workspace.dependencies.serde]
|
||||
version = "1.0.225"
|
||||
version = "1.0.228"
|
||||
features = ["derive"] # Most of the time, if we need serde, we need derive
|
||||
|
||||
# JSON serialization and deserialization
|
||||
@@ -652,7 +652,7 @@ version = "0.1.17"
|
||||
|
||||
# Tokio rustls integration
|
||||
[workspace.dependencies.tokio-rustls]
|
||||
version = "0.26.3"
|
||||
version = "0.26.4"
|
||||
|
||||
# Tokio test utilities
|
||||
[workspace.dependencies.tokio-test]
|
||||
|
||||
@@ -390,9 +390,10 @@ impl Options {
|
||||
info!("The following users can request admin privileges ({total} total):");
|
||||
loop {
|
||||
let page = repo.user().list(filter, cursor).await?;
|
||||
for user in page.edges {
|
||||
for edge in page.edges {
|
||||
let user = edge.node;
|
||||
info!(%user.id, username = %user.username);
|
||||
cursor = cursor.after(user.id);
|
||||
cursor = cursor.after(edge.cursor);
|
||||
}
|
||||
|
||||
if !page.has_next_page {
|
||||
|
||||
@@ -132,7 +132,8 @@ pub async fn config_sync(
|
||||
let mut existing_enabled_ids = BTreeSet::new();
|
||||
let mut existing_disabled = BTreeMap::new();
|
||||
// Process the existing providers
|
||||
for provider in page.edges {
|
||||
for edge in page.edges {
|
||||
let provider = edge.node;
|
||||
if provider.enabled() {
|
||||
if config_ids.contains(&provider.id) {
|
||||
existing_enabled_ids.insert(provider.id);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
use mas_storage::Pagination;
|
||||
use mas_storage::{Pagination, pagination::Edge};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use ulid::Ulid;
|
||||
@@ -119,7 +119,7 @@ impl<T: Resource> PaginatedResponse<T> {
|
||||
base,
|
||||
current_pagination
|
||||
.clear_before()
|
||||
.after(page.edges.last().unwrap().id()),
|
||||
.after(page.edges.last().unwrap().cursor),
|
||||
)
|
||||
}),
|
||||
prev: if page.has_previous_page {
|
||||
@@ -127,14 +127,18 @@ impl<T: Resource> PaginatedResponse<T> {
|
||||
base,
|
||||
current_pagination
|
||||
.clear_after()
|
||||
.before(page.edges.first().unwrap().id()),
|
||||
.before(page.edges.first().unwrap().cursor),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
};
|
||||
|
||||
let data = page.edges.into_iter().map(SingleResource::new).collect();
|
||||
let data = page
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(SingleResource::from_edge)
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
meta: PaginationMeta { count },
|
||||
@@ -176,6 +180,31 @@ struct SingleResource<T> {
|
||||
|
||||
/// Related links
|
||||
links: SelfLinks,
|
||||
|
||||
/// Metadata about the resource
|
||||
#[serde(skip_serializing_if = "SingleResourceMeta::is_empty")]
|
||||
meta: SingleResourceMeta,
|
||||
}
|
||||
|
||||
/// Metadata associated with a resource
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
struct SingleResourceMeta {
|
||||
/// Information about the pagination of the resource
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
page: Option<SingleResourceMetaPage>,
|
||||
}
|
||||
|
||||
impl SingleResourceMeta {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.page.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Pagination metadata for a resource
|
||||
#[derive(Serialize, JsonSchema)]
|
||||
struct SingleResourceMetaPage {
|
||||
/// The cursor of this resource in the paginated result
|
||||
cursor: String,
|
||||
}
|
||||
|
||||
impl<T: Resource> SingleResource<T> {
|
||||
@@ -186,8 +215,16 @@ impl<T: Resource> SingleResource<T> {
|
||||
id: resource.id(),
|
||||
attributes: resource,
|
||||
links: SelfLinks { self_ },
|
||||
meta: SingleResourceMeta { page: None },
|
||||
}
|
||||
}
|
||||
|
||||
fn from_edge<C: ToString>(edge: Edge<T, C>) -> Self {
|
||||
let cursor = edge.cursor.to_string();
|
||||
let mut resource = Self::new(edge.node);
|
||||
resource.meta.page = Some(SingleResourceMetaPage { cursor });
|
||||
resource
|
||||
}
|
||||
}
|
||||
|
||||
/// Related links
|
||||
|
||||
@@ -137,7 +137,13 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p
|
||||
let sessions = CompatSession::samples();
|
||||
let pagination = mas_storage::Pagination::first(sessions.len());
|
||||
let page = Page {
|
||||
edges: sessions.into(),
|
||||
edges: sessions
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -316,6 +322,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -335,6 +346,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNCZP0PPF7X0EVMJNECPZW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNCZP0PPF7X0EVMJNECPZW"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -379,6 +395,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -420,6 +441,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -461,6 +487,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNCZP0PPF7X0EVMJNECPZW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNCZP0PPF7X0EVMJNECPZW"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -499,6 +530,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -518,6 +554,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNCZP0PPF7X0EVMJNECPZW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNCZP0PPF7X0EVMJNECPZW"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -577,6 +618,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AAPR7PEV8KNBZD5Y"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -192,7 +192,13 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p
|
||||
let sessions = OAuth2Session::samples();
|
||||
let pagination = mas_storage::Pagination::first(sessions.len());
|
||||
let page = Page {
|
||||
edges: sessions.into(),
|
||||
edges: sessions
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -371,6 +377,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions/01FSHN9AG0MKGTBNZ16RDR3PVY"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MKGTBNZ16RDR3PVY"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -409,6 +420,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions/01FSHN9AG0MKGTBNZ16RDR3PVY"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MKGTBNZ16RDR3PVY"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -112,7 +112,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation {
|
||||
let links = UpstreamOAuthLink::samples();
|
||||
let pagination = mas_storage::Pagination::first(links.len());
|
||||
let page = Page {
|
||||
edges: links.into(),
|
||||
edges: links
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -313,7 +319,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 3
|
||||
@@ -331,6 +337,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -345,6 +356,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0PJZ6DZNTAA1XKPT4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -359,6 +375,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -368,7 +389,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/upstream-oauth-links?page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by user ID
|
||||
let request = Request::get(format!(
|
||||
@@ -381,7 +402,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
@@ -399,6 +420,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -413,6 +439,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -422,7 +453,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by provider
|
||||
let request = Request::get(format!(
|
||||
@@ -435,7 +466,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
@@ -453,6 +484,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -467,6 +503,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0PJZ6DZNTAA1XKPT4"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -476,7 +517,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/upstream-oauth-links?filter[provider]=01FSHN9AG09NMZYX8MFYH578R9&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by subject
|
||||
let request = Request::get(format!(
|
||||
@@ -489,7 +530,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
@@ -507,6 +548,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -516,7 +562,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/upstream-oauth-links?filter[subject]=subject1&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/upstream-oauth-links?count=false")
|
||||
@@ -525,7 +571,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
@@ -540,6 +586,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -554,6 +605,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0PJZ6DZNTAA1XKPT4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -568,6 +624,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -577,7 +638,7 @@ mod tests {
|
||||
"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")
|
||||
@@ -622,6 +683,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AQZQP8DX40GD59PW"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -636,6 +702,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0QHEHKX2JNQ2A2D07"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -84,7 +84,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation {
|
||||
let providers = UpstreamOAuthProvider::samples();
|
||||
let pagination = mas_storage::Pagination::first(providers.len());
|
||||
let page = Page {
|
||||
edges: providers.into(),
|
||||
edges: providers
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -305,6 +311,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -319,6 +330,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -333,6 +349,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -378,6 +399,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -392,6 +418,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -437,6 +468,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -483,6 +519,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -497,6 +538,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -539,6 +585,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -596,6 +647,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -610,6 +666,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -624,6 +685,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -678,6 +744,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -692,6 +763,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -99,7 +99,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation {
|
||||
let emails = UserEmail::samples();
|
||||
let pagination = mas_storage::Pagination::first(emails.len());
|
||||
let page = Page {
|
||||
edges: emails.into(),
|
||||
edges: emails
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -226,7 +232,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
@@ -242,6 +248,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09NMZYX8MFYH578R9"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -254,6 +265,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG0KEPHYQQXW9XPTX6Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0KEPHYQQXW9XPTX6Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -263,7 +279,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/user-emails?page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by user
|
||||
let request = Request::get(format!(
|
||||
@@ -275,7 +291,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
@@ -291,6 +307,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09NMZYX8MFYH578R9"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -300,7 +321,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by email
|
||||
let request = Request::get("/api/admin/v1/user-emails?filter[email]=alice@example.com")
|
||||
@@ -309,7 +330,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
@@ -325,6 +346,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09NMZYX8MFYH578R9"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -334,7 +360,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/user-emails?filter[email]=alice@example.com&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/user-emails?count=false")
|
||||
@@ -343,7 +369,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
@@ -356,6 +382,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09NMZYX8MFYH578R9"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -368,6 +399,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG0KEPHYQQXW9XPTX6Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0KEPHYQQXW9XPTX6Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -377,7 +413,7 @@ mod tests {
|
||||
"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")
|
||||
@@ -420,6 +456,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09NMZYX8MFYH578R9"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -112,7 +112,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation {
|
||||
let tokens = UserRegistrationToken::samples();
|
||||
let pagination = mas_storage::Pagination::first(tokens.len());
|
||||
let page = Page {
|
||||
edges: tokens.into(),
|
||||
edges: tokens
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -314,6 +320,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -331,6 +342,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -348,6 +364,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -365,6 +386,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -382,6 +408,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -430,6 +461,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -447,6 +483,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -487,6 +528,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -504,6 +550,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -521,6 +572,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -569,6 +625,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -586,6 +647,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -626,6 +692,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -643,6 +714,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -660,6 +736,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -708,6 +789,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -748,6 +834,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -765,6 +856,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -782,6 +878,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -799,6 +900,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -847,6 +953,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -864,6 +975,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -904,6 +1020,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -921,6 +1042,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -938,6 +1064,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -988,6 +1119,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1036,6 +1172,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1053,6 +1194,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1094,6 +1240,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1111,6 +1262,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1152,6 +1308,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1219,6 +1380,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG064K8BYZXSY5G511Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1236,6 +1402,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1253,6 +1424,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG09AVTNSQFMSR34AJC"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1270,6 +1446,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1287,6 +1468,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1342,6 +1528,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG07HNEZXNQM2KNBNF6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1359,6 +1550,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -123,7 +123,13 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p
|
||||
let sessions = UserSession::samples();
|
||||
let pagination = mas_storage::Pagination::first(sessions.len());
|
||||
let page = Page {
|
||||
edges: sessions.into(),
|
||||
edges: sessions
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -258,7 +264,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 2
|
||||
@@ -277,6 +283,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -292,6 +303,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB530KEPHYQQXW9XPTX6Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AJ6AC5HQ9X6H4RP4"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -301,7 +317,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/user-sessions?page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by user
|
||||
let request = Request::get(format!(
|
||||
@@ -313,7 +329,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
@@ -332,6 +348,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -341,7 +362,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by status (active)
|
||||
let request = Request::get("/api/admin/v1/user-sessions?filter[status]=active")
|
||||
@@ -350,7 +371,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
@@ -369,6 +390,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -378,7 +404,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/user-sessions?filter[status]=active&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Filter by status (finished)
|
||||
let request = Request::get("/api/admin/v1/user-sessions?filter[status]=finished")
|
||||
@@ -387,7 +413,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"meta": {
|
||||
"count": 1
|
||||
@@ -406,6 +432,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB530KEPHYQQXW9XPTX6Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AJ6AC5HQ9X6H4RP4"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -415,7 +446,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/user-sessions?filter[status]=finished&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Test count=false
|
||||
let request = Request::get("/api/admin/v1/user-sessions?count=false")
|
||||
@@ -424,7 +455,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
@@ -440,6 +471,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -455,6 +491,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB530KEPHYQQXW9XPTX6Z"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHNB530AJ6AC5HQ9X6H4RP4"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -464,7 +505,7 @@ mod tests {
|
||||
"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")
|
||||
@@ -510,6 +551,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -137,7 +137,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation {
|
||||
let users = User::samples();
|
||||
let pagination = mas_storage::Pagination::first(users.len());
|
||||
let page = Page {
|
||||
edges: users.into(),
|
||||
edges: users
|
||||
.into_iter()
|
||||
.map(|node| mas_storage::pagination::Edge {
|
||||
cursor: node.id(),
|
||||
node,
|
||||
})
|
||||
.collect(),
|
||||
has_next_page: true,
|
||||
has_previous_page: false,
|
||||
};
|
||||
@@ -255,6 +261,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0AJ6AC5HQ9X6H4RP4"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AJ6AC5HQ9X6H4RP4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -270,6 +281,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -288,7 +304,7 @@ mod tests {
|
||||
let response = state.request(request).await;
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
insta::assert_json_snapshot!(body, @r###"
|
||||
insta::assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
@@ -304,6 +320,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0AJ6AC5HQ9X6H4RP4"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0AJ6AC5HQ9X6H4RP4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -319,6 +340,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -328,7 +354,7 @@ mod tests {
|
||||
"last": "/api/admin/v1/users?count=false&page[last]=10"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
|
||||
// Test count=only
|
||||
let request = Request::get("/api/admin/v1/users?count=only")
|
||||
@@ -371,6 +397,11 @@ mod tests {
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -172,7 +172,7 @@ impl BrowserSession {
|
||||
|
||||
connection
|
||||
.edges
|
||||
.extend(page.edges.into_iter().map(|s| match s {
|
||||
.extend(page.edges.into_iter().map(|edge| match edge.node {
|
||||
mas_storage::app_session::AppSession::Compat(session) => Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)),
|
||||
AppSession::CompatSession(Box::new(CompatSession::new(*session))),
|
||||
|
||||
@@ -125,10 +125,10 @@ impl User {
|
||||
page.has_next_page,
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
connection.edges.extend(page.edges.into_iter().map(|u| {
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::CompatSsoLogin, u.id)),
|
||||
CompatSsoLogin(u),
|
||||
OpaqueCursor(NodeCursor(NodeType::CompatSsoLogin, edge.cursor)),
|
||||
CompatSsoLogin(edge.node),
|
||||
)
|
||||
}));
|
||||
|
||||
@@ -219,14 +219,13 @@ impl User {
|
||||
page.has_next_page,
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
connection
|
||||
.edges
|
||||
.extend(page.edges.into_iter().map(|(session, sso_login)| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)),
|
||||
CompatSession::new(session).with_loaded_sso_login(sso_login),
|
||||
)
|
||||
}));
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
let (session, sso_login) = edge.node;
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)),
|
||||
CompatSession::new(session).with_loaded_sso_login(sso_login),
|
||||
)
|
||||
}));
|
||||
|
||||
Ok::<_, async_graphql::Error>(connection)
|
||||
},
|
||||
@@ -305,10 +304,10 @@ impl User {
|
||||
page.has_next_page,
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
connection.edges.extend(page.edges.into_iter().map(|u| {
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::BrowserSession, u.id)),
|
||||
BrowserSession(u),
|
||||
OpaqueCursor(NodeCursor(NodeType::BrowserSession, edge.cursor)),
|
||||
BrowserSession(edge.node),
|
||||
)
|
||||
}));
|
||||
|
||||
@@ -373,10 +372,10 @@ impl User {
|
||||
page.has_next_page,
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
connection.edges.extend(page.edges.into_iter().map(|u| {
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::UserEmail, u.id)),
|
||||
UserEmail(u),
|
||||
OpaqueCursor(NodeCursor(NodeType::UserEmail, edge.cursor)),
|
||||
UserEmail(edge.node),
|
||||
)
|
||||
}));
|
||||
|
||||
@@ -480,10 +479,10 @@ impl User {
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
|
||||
connection.edges.extend(page.edges.into_iter().map(|s| {
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::OAuth2Session, s.id)),
|
||||
OAuth2Session(s),
|
||||
OpaqueCursor(NodeCursor(NodeType::OAuth2Session, edge.cursor)),
|
||||
OAuth2Session(edge.node),
|
||||
)
|
||||
}));
|
||||
|
||||
@@ -547,10 +546,10 @@ impl User {
|
||||
page.has_next_page,
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
connection.edges.extend(page.edges.into_iter().map(|s| {
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Link, s.id)),
|
||||
UpstreamOAuth2Link::new(s),
|
||||
OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Link, edge.cursor)),
|
||||
UpstreamOAuth2Link::new(edge.node),
|
||||
)
|
||||
}));
|
||||
|
||||
@@ -689,13 +688,13 @@ impl User {
|
||||
|
||||
connection
|
||||
.edges
|
||||
.extend(page.edges.into_iter().map(|s| match s {
|
||||
.extend(page.edges.into_iter().map(|edge| match edge.node {
|
||||
mas_storage::app_session::AppSession::Compat(session) => Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)),
|
||||
OpaqueCursor(NodeCursor(NodeType::CompatSession, edge.cursor)),
|
||||
AppSession::CompatSession(Box::new(CompatSession::new(*session))),
|
||||
),
|
||||
mas_storage::app_session::AppSession::OAuth2(session) => Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::OAuth2Session, session.id)),
|
||||
OpaqueCursor(NodeCursor(NodeType::OAuth2Session, edge.cursor)),
|
||||
AppSession::OAuth2Session(Box::new(OAuth2Session(*session))),
|
||||
),
|
||||
}));
|
||||
|
||||
@@ -68,7 +68,8 @@ impl SessionQuery {
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((compat_session, sso_login)) = compat_sessions.edges.into_iter().next() {
|
||||
if let Some(edge) = compat_sessions.edges.into_iter().next() {
|
||||
let (compat_session, sso_login) = edge.node;
|
||||
repo.cancel().await?;
|
||||
|
||||
return Ok(Some(Session::CompatSession(Box::new(
|
||||
@@ -92,10 +93,10 @@ impl SessionQuery {
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(session) = sessions.edges.into_iter().next() {
|
||||
if let Some(edge) = sessions.edges.into_iter().next() {
|
||||
repo.cancel().await?;
|
||||
return Ok(Some(Session::OAuth2Session(Box::new(OAuth2Session(
|
||||
session,
|
||||
edge.node,
|
||||
)))));
|
||||
}
|
||||
repo.cancel().await?;
|
||||
|
||||
@@ -130,10 +130,10 @@ impl UpstreamOAuthQuery {
|
||||
page.has_next_page,
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
connection.edges.extend(page.edges.into_iter().map(|p| {
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Provider, p.id)),
|
||||
UpstreamOAuth2Provider::new(p),
|
||||
OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Provider, edge.cursor)),
|
||||
UpstreamOAuth2Provider::new(edge.node),
|
||||
)
|
||||
}));
|
||||
|
||||
|
||||
@@ -143,11 +143,12 @@ impl UserQuery {
|
||||
page.has_next_page,
|
||||
PreloadedTotalCount(count),
|
||||
);
|
||||
connection.edges.extend(
|
||||
page.edges.into_iter().map(|p| {
|
||||
Edge::new(OpaqueCursor(NodeCursor(NodeType::User, p.id)), User(p))
|
||||
}),
|
||||
);
|
||||
connection.edges.extend(page.edges.into_iter().map(|edge| {
|
||||
Edge::new(
|
||||
OpaqueCursor(NodeCursor(NodeType::User, edge.cursor)),
|
||||
User(edge.node),
|
||||
)
|
||||
}));
|
||||
|
||||
Ok::<_, async_graphql::Error>(connection)
|
||||
},
|
||||
|
||||
@@ -267,9 +267,9 @@ pub(crate) async fn post(
|
||||
.browser_session()
|
||||
.list(browser_session_filter, cursor)
|
||||
.await?;
|
||||
for browser_session in browser_sessions.edges {
|
||||
user_ids.insert(browser_session.user.id);
|
||||
cursor = cursor.after(browser_session.id);
|
||||
for edge in browser_sessions.edges {
|
||||
user_ids.insert(edge.node.user.id);
|
||||
cursor = cursor.after(edge.cursor);
|
||||
}
|
||||
|
||||
if !browser_sessions.has_next_page {
|
||||
|
||||
@@ -1212,9 +1212,9 @@ mod tests {
|
||||
.list(UserEmailFilter::new().for_user(&user), Pagination::first(1))
|
||||
.await
|
||||
.unwrap();
|
||||
let email = page.edges.first().expect("email exists");
|
||||
let edge = page.edges.first().expect("email exists");
|
||||
|
||||
assert_eq!(email.email, "john@example.com");
|
||||
assert_eq!(edge.node.email, "john@example.com");
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
|
||||
@@ -55,7 +55,9 @@ mod priv_ {
|
||||
use std::net::IpAddr;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use mas_storage::pagination::Node;
|
||||
use sea_query::enum_def;
|
||||
use ulid::Ulid;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
@@ -77,6 +79,12 @@ mod priv_ {
|
||||
pub(super) last_active_at: Option<DateTime<Utc>>,
|
||||
pub(super) last_active_ip: Option<IpAddr>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for AppSessionLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.cursor.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use priv_::{AppSessionLookup, AppSessionLookupIden};
|
||||
@@ -592,13 +600,13 @@ mod tests {
|
||||
let full_list = repo.app_session().list(all, pagination).await.unwrap();
|
||||
assert_eq!(full_list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
full_list.edges[0],
|
||||
full_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
let active_list = repo.app_session().list(active, pagination).await.unwrap();
|
||||
assert_eq!(active_list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
active_list.edges[0],
|
||||
active_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
let finished_list = repo.app_session().list(finished, pagination).await.unwrap();
|
||||
@@ -618,7 +626,7 @@ mod tests {
|
||||
let full_list = repo.app_session().list(all, pagination).await.unwrap();
|
||||
assert_eq!(full_list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
full_list.edges[0],
|
||||
full_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
let active_list = repo.app_session().list(active, pagination).await.unwrap();
|
||||
@@ -626,7 +634,7 @@ mod tests {
|
||||
let finished_list = repo.app_session().list(finished, pagination).await.unwrap();
|
||||
assert_eq!(finished_list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
finished_list.edges[0],
|
||||
finished_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
|
||||
@@ -680,25 +688,25 @@ mod tests {
|
||||
let full_list = repo.app_session().list(all, pagination).await.unwrap();
|
||||
assert_eq!(full_list.edges.len(), 2);
|
||||
assert_eq!(
|
||||
full_list.edges[0],
|
||||
full_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
assert_eq!(
|
||||
full_list.edges[1],
|
||||
full_list.edges[1].node,
|
||||
AppSession::OAuth2(Box::new(oauth_session.clone()))
|
||||
);
|
||||
|
||||
let active_list = repo.app_session().list(active, pagination).await.unwrap();
|
||||
assert_eq!(active_list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
active_list.edges[0],
|
||||
active_list.edges[0].node,
|
||||
AppSession::OAuth2(Box::new(oauth_session.clone()))
|
||||
);
|
||||
|
||||
let finished_list = repo.app_session().list(finished, pagination).await.unwrap();
|
||||
assert_eq!(finished_list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
finished_list.edges[0],
|
||||
finished_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
|
||||
@@ -716,11 +724,11 @@ mod tests {
|
||||
let full_list = repo.app_session().list(all, pagination).await.unwrap();
|
||||
assert_eq!(full_list.edges.len(), 2);
|
||||
assert_eq!(
|
||||
full_list.edges[0],
|
||||
full_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
assert_eq!(
|
||||
full_list.edges[1],
|
||||
full_list.edges[1].node,
|
||||
AppSession::OAuth2(Box::new(oauth_session.clone()))
|
||||
);
|
||||
|
||||
@@ -730,11 +738,11 @@ mod tests {
|
||||
let finished_list = repo.app_session().list(finished, pagination).await.unwrap();
|
||||
assert_eq!(finished_list.edges.len(), 2);
|
||||
assert_eq!(
|
||||
finished_list.edges[0],
|
||||
finished_list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
assert_eq!(
|
||||
full_list.edges[1],
|
||||
full_list.edges[1].node,
|
||||
AppSession::OAuth2(Box::new(oauth_session.clone()))
|
||||
);
|
||||
|
||||
@@ -744,7 +752,7 @@ mod tests {
|
||||
let list = repo.app_session().list(filter, pagination).await.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
list.edges[0],
|
||||
list.edges[0].node,
|
||||
AppSession::Compat(Box::new(compat_session.clone()))
|
||||
);
|
||||
|
||||
@@ -753,7 +761,7 @@ mod tests {
|
||||
let list = repo.app_session().list(filter, pagination).await.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(
|
||||
list.edges[0],
|
||||
list.edges[0].node,
|
||||
AppSession::OAuth2(Box::new(oauth_session.clone()))
|
||||
);
|
||||
|
||||
|
||||
@@ -92,14 +92,14 @@ mod tests {
|
||||
|
||||
let full_list = repo.compat_session().list(all, pagination).await.unwrap();
|
||||
assert_eq!(full_list.edges.len(), 1);
|
||||
assert_eq!(full_list.edges[0].0.id, session.id);
|
||||
assert_eq!(full_list.edges[0].node.0.id, session.id);
|
||||
let active_list = repo
|
||||
.compat_session()
|
||||
.list(active, pagination)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(active_list.edges.len(), 1);
|
||||
assert_eq!(active_list.edges[0].0.id, session.id);
|
||||
assert_eq!(active_list.edges[0].node.0.id, session.id);
|
||||
let finished_list = repo
|
||||
.compat_session()
|
||||
.list(finished, pagination)
|
||||
@@ -150,7 +150,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
let session_lookup = &list.edges[0].0;
|
||||
let session_lookup = &list.edges[0].node.0;
|
||||
assert_eq!(session_lookup.id, session.id);
|
||||
assert_eq!(session_lookup.user_id, user.id);
|
||||
assert_eq!(session.device.as_ref().unwrap().as_str(), device_str);
|
||||
@@ -168,7 +168,7 @@ mod tests {
|
||||
|
||||
let full_list = repo.compat_session().list(all, pagination).await.unwrap();
|
||||
assert_eq!(full_list.edges.len(), 1);
|
||||
assert_eq!(full_list.edges[0].0.id, session.id);
|
||||
assert_eq!(full_list.edges[0].node.0.id, session.id);
|
||||
let active_list = repo
|
||||
.compat_session()
|
||||
.list(active, pagination)
|
||||
@@ -181,7 +181,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(finished_list.edges.len(), 1);
|
||||
assert_eq!(finished_list.edges[0].0.id, session.id);
|
||||
assert_eq!(finished_list.edges[0].node.0.id, session.id);
|
||||
|
||||
// Reload the session and check again
|
||||
let session_lookup = repo
|
||||
@@ -260,14 +260,14 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0].0.id, sso_login_session.id);
|
||||
assert_eq!(list.edges[0].node.0.id, sso_login_session.id);
|
||||
let list = repo
|
||||
.compat_session()
|
||||
.list(unknown, pagination)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0].0.id, unknown_session.id);
|
||||
assert_eq!(list.edges[0].node.0.id, unknown_session.id);
|
||||
|
||||
// Check that combining the two filters works
|
||||
// At this point, there is one active SSO login session and one finished unknown
|
||||
@@ -696,7 +696,8 @@ mod tests {
|
||||
// List all logins
|
||||
let logins = repo.compat_sso_login().list(all, pagination).await.unwrap();
|
||||
assert!(!logins.has_next_page);
|
||||
assert_eq!(logins.edges, vec![login.clone()]);
|
||||
assert_eq!(logins.edges.len(), 1);
|
||||
assert_eq!(logins.edges[0].node, login);
|
||||
|
||||
// List the logins for the user
|
||||
let logins = repo
|
||||
@@ -705,7 +706,8 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(!logins.has_next_page);
|
||||
assert_eq!(logins.edges, vec![login.clone()]);
|
||||
assert_eq!(logins.edges.len(), 1);
|
||||
assert_eq!(logins.edges[0].node, login);
|
||||
|
||||
// List only the pending logins for the user
|
||||
let logins = repo
|
||||
@@ -732,6 +734,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(!logins.has_next_page);
|
||||
assert_eq!(logins.edges, &[login]);
|
||||
assert_eq!(logins.edges.len(), 1);
|
||||
assert_eq!(logins.edges[0].node, login);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use mas_data_model::{
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
compat::{CompatSessionFilter, CompatSessionRepository},
|
||||
pagination::Node,
|
||||
};
|
||||
use rand::RngCore;
|
||||
use sea_query::{Expr, PostgresQueryBuilder, Query, enum_def};
|
||||
@@ -59,6 +60,12 @@ struct CompatSessionLookup {
|
||||
last_active_ip: Option<IpAddr>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for CompatSessionLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.compat_session_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompatSessionLookup> for CompatSession {
|
||||
fn from(value: CompatSessionLookup) -> Self {
|
||||
let id = value.compat_session_id.into();
|
||||
@@ -106,6 +113,12 @@ struct CompatSessionAndSsoLoginLookup {
|
||||
compat_sso_login_exchanged_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for CompatSessionAndSsoLoginLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.compat_session_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<CompatSessionAndSsoLoginLookup> for (CompatSession, Option<CompatSsoLogin>) {
|
||||
type Error = DatabaseInconsistencyError;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use mas_data_model::{BrowserSession, Clock, CompatSession, CompatSsoLogin, Compa
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
compat::{CompatSsoLoginFilter, CompatSsoLoginRepository},
|
||||
pagination::Node,
|
||||
};
|
||||
use rand::RngCore;
|
||||
use sea_query::{Expr, PostgresQueryBuilder, Query, enum_def};
|
||||
@@ -54,6 +55,12 @@ struct CompatSsoLoginLookup {
|
||||
compat_session_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for CompatSsoLoginLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.compat_sso_login_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<CompatSsoLoginLookup> for CompatSsoLogin {
|
||||
type Error = DatabaseInconsistencyError;
|
||||
|
||||
|
||||
@@ -511,10 +511,10 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 4);
|
||||
assert_eq!(list.edges[0], session11);
|
||||
assert_eq!(list.edges[1], session12);
|
||||
assert_eq!(list.edges[2], session21);
|
||||
assert_eq!(list.edges[3], session22);
|
||||
assert_eq!(list.edges[0].node, session11);
|
||||
assert_eq!(list.edges[1].node, session12);
|
||||
assert_eq!(list.edges[2].node, session21);
|
||||
assert_eq!(list.edges[3].node, session22);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 4);
|
||||
|
||||
@@ -527,8 +527,8 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 2);
|
||||
assert_eq!(list.edges[0], session11);
|
||||
assert_eq!(list.edges[1], session21);
|
||||
assert_eq!(list.edges[0].node, session11);
|
||||
assert_eq!(list.edges[1].node, session21);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2);
|
||||
|
||||
@@ -541,8 +541,8 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 2);
|
||||
assert_eq!(list.edges[0], session11);
|
||||
assert_eq!(list.edges[1], session12);
|
||||
assert_eq!(list.edges[0].node, session11);
|
||||
assert_eq!(list.edges[1].node, session12);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2);
|
||||
|
||||
@@ -557,7 +557,7 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0], session22);
|
||||
assert_eq!(list.edges[0].node, session22);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1);
|
||||
|
||||
@@ -570,8 +570,8 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 2);
|
||||
assert_eq!(list.edges[0], session12);
|
||||
assert_eq!(list.edges[1], session21);
|
||||
assert_eq!(list.edges[0].node, session12);
|
||||
assert_eq!(list.edges[1].node, session21);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2);
|
||||
|
||||
@@ -584,8 +584,8 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 2);
|
||||
assert_eq!(list.edges[0], session11);
|
||||
assert_eq!(list.edges[1], session22);
|
||||
assert_eq!(list.edges[0].node, session11);
|
||||
assert_eq!(list.edges[1].node, session22);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2);
|
||||
|
||||
@@ -598,7 +598,7 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0], session22);
|
||||
assert_eq!(list.edges[0].node, session22);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1);
|
||||
|
||||
@@ -613,7 +613,7 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0], session22);
|
||||
assert_eq!(list.edges[0].node, session22);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1);
|
||||
|
||||
@@ -626,7 +626,7 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0], session12);
|
||||
assert_eq!(list.edges[0].node, session12);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1);
|
||||
|
||||
@@ -641,7 +641,7 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0], session21);
|
||||
assert_eq!(list.edges[0].node, session21);
|
||||
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1);
|
||||
|
||||
@@ -655,10 +655,10 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 4);
|
||||
assert_eq!(list.edges[0], session11);
|
||||
assert_eq!(list.edges[1], session12);
|
||||
assert_eq!(list.edges[2], session21);
|
||||
assert_eq!(list.edges[3], session22);
|
||||
assert_eq!(list.edges[0].node, session11);
|
||||
assert_eq!(list.edges[1].node, session12);
|
||||
assert_eq!(list.edges[2].node, session21);
|
||||
assert_eq!(list.edges[3].node, session22);
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 4);
|
||||
|
||||
// We should get all sessions with the "openid" and "email" scope
|
||||
@@ -671,8 +671,8 @@ mod tests {
|
||||
.unwrap();
|
||||
assert!(!list.has_next_page);
|
||||
assert_eq!(list.edges.len(), 2);
|
||||
assert_eq!(list.edges[0], session11);
|
||||
assert_eq!(list.edges[1], session12);
|
||||
assert_eq!(list.edges[0].node, session11);
|
||||
assert_eq!(list.edges[1].node, session12);
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2);
|
||||
|
||||
// Try combining the scope filter with the user filter
|
||||
@@ -685,7 +685,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0], session11);
|
||||
assert_eq!(list.edges[0].node, session11);
|
||||
assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1);
|
||||
|
||||
// Finish all sessions of a client in batch
|
||||
|
||||
@@ -12,6 +12,7 @@ use mas_data_model::{BrowserSession, Client, Clock, Session, SessionState, User}
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
oauth2::{OAuth2SessionFilter, OAuth2SessionRepository},
|
||||
pagination::Node,
|
||||
};
|
||||
use oauth2_types::scope::{Scope, ScopeToken};
|
||||
use rand::RngCore;
|
||||
@@ -61,6 +62,12 @@ struct OAuthSessionLookup {
|
||||
human_name: Option<String>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for OAuthSessionLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.oauth2_session_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OAuthSessionLookup> for Session {
|
||||
type Error = DatabaseInconsistencyError;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use chrono::{DateTime, Utc};
|
||||
use mas_data_model::{Clock, UpstreamOAuthLink, UpstreamOAuthProvider, User};
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
pagination::Node,
|
||||
upstream_oauth2::{UpstreamOAuthLinkFilter, UpstreamOAuthLinkRepository},
|
||||
};
|
||||
use opentelemetry_semantic_conventions::trace::DB_QUERY_TEXT;
|
||||
@@ -53,6 +54,12 @@ struct LinkLookup {
|
||||
created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for LinkLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.upstream_oauth_link_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LinkLookup> for UpstreamOAuthLink {
|
||||
fn from(value: LinkLookup) -> Self {
|
||||
UpstreamOAuthLink {
|
||||
|
||||
@@ -206,8 +206,8 @@ mod tests {
|
||||
assert!(!links.has_previous_page);
|
||||
assert!(!links.has_next_page);
|
||||
assert_eq!(links.edges.len(), 1);
|
||||
assert_eq!(links.edges[0].id, link.id);
|
||||
assert_eq!(links.edges[0].user_id, Some(user.id));
|
||||
assert_eq!(links.edges[0].node.id, link.id);
|
||||
assert_eq!(links.edges[0].node.user_id, Some(user.id));
|
||||
|
||||
assert_eq!(repo.upstream_oauth_link().count(filter).await.unwrap(), 1);
|
||||
|
||||
@@ -282,7 +282,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(session_page.edges.len(), 1);
|
||||
assert_eq!(session_page.edges[0].id, session.id);
|
||||
assert_eq!(session_page.edges[0].node.id, session.id);
|
||||
assert!(!session_page.has_next_page);
|
||||
assert!(!session_page.has_previous_page);
|
||||
|
||||
@@ -374,7 +374,7 @@ mod tests {
|
||||
|
||||
// It returned the first 10 items
|
||||
assert!(page.has_next_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[..10]);
|
||||
|
||||
// Getting the same page with the "enabled only" filter should return the same
|
||||
@@ -396,7 +396,7 @@ mod tests {
|
||||
|
||||
// It returned the next 10 items
|
||||
assert!(!page.has_next_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[10..]);
|
||||
|
||||
// Lookup the last 10 items
|
||||
@@ -408,7 +408,7 @@ mod tests {
|
||||
|
||||
// It returned the last 10 items
|
||||
assert!(page.has_previous_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[10..]);
|
||||
|
||||
// Lookup the previous 10 items
|
||||
@@ -420,7 +420,7 @@ mod tests {
|
||||
|
||||
// It returned the previous 10 items
|
||||
assert!(!page.has_previous_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[..10]);
|
||||
|
||||
// Lookup 10 items between two IDs
|
||||
@@ -432,7 +432,7 @@ mod tests {
|
||||
|
||||
// It returned the items in between
|
||||
assert!(!page.has_next_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[6..8]);
|
||||
|
||||
// There should not be any disabled providers
|
||||
@@ -560,7 +560,7 @@ mod tests {
|
||||
|
||||
// It returned the first 10 items
|
||||
assert!(page.has_next_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[..10]);
|
||||
|
||||
// Lookup the next 10 items
|
||||
@@ -572,7 +572,7 @@ mod tests {
|
||||
|
||||
// It returned the next 10 items
|
||||
assert!(!page.has_next_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[10..]);
|
||||
|
||||
// Lookup the last 10 items
|
||||
@@ -584,7 +584,7 @@ mod tests {
|
||||
|
||||
// It returned the last 10 items
|
||||
assert!(page.has_previous_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[10..]);
|
||||
|
||||
// Lookup the previous 10 items
|
||||
@@ -596,7 +596,7 @@ mod tests {
|
||||
|
||||
// It returned the previous 10 items
|
||||
assert!(!page.has_previous_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[..10]);
|
||||
|
||||
// Lookup 5 items between two IDs
|
||||
@@ -608,7 +608,7 @@ mod tests {
|
||||
|
||||
// It returned the items in between
|
||||
assert!(!page.has_next_page);
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect();
|
||||
let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect();
|
||||
assert_eq!(&edge_ids, &ids[6..11]);
|
||||
|
||||
// Check the sub/sid filters
|
||||
@@ -638,11 +638,21 @@ mod tests {
|
||||
assert_eq!(page.edges.len(), 4);
|
||||
for edge in page.edges {
|
||||
assert_eq!(
|
||||
edge.id_token_claims().unwrap().get("sub").unwrap().as_str(),
|
||||
edge.node
|
||||
.id_token_claims()
|
||||
.unwrap()
|
||||
.get("sub")
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
Some("alice")
|
||||
);
|
||||
assert_eq!(
|
||||
edge.id_token_claims().unwrap().get("sid").unwrap().as_str(),
|
||||
edge.node
|
||||
.id_token_claims()
|
||||
.unwrap()
|
||||
.get("sid")
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
Some("one")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use chrono::{DateTime, Utc};
|
||||
use mas_data_model::{Clock, UpstreamOAuthProvider, UpstreamOAuthProviderClaimsImports};
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
pagination::Node,
|
||||
upstream_oauth2::{
|
||||
UpstreamOAuthProviderFilter, UpstreamOAuthProviderParams, UpstreamOAuthProviderRepository,
|
||||
},
|
||||
@@ -74,6 +75,12 @@ struct ProviderLookup {
|
||||
on_backchannel_logout: String,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for ProviderLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.upstream_oauth_provider_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ProviderLookup> for UpstreamOAuthProvider {
|
||||
type Error = DatabaseInconsistencyError;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use mas_data_model::{
|
||||
};
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
pagination::Node,
|
||||
upstream_oauth2::{UpstreamOAuthSessionFilter, UpstreamOAuthSessionRepository},
|
||||
};
|
||||
use rand::RngCore;
|
||||
@@ -91,6 +92,12 @@ struct SessionLookup {
|
||||
unlinked_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for SessionLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.upstream_oauth_authorization_session_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SessionLookup> for UpstreamOAuthAuthorizationSession {
|
||||
type Error = DatabaseInconsistencyError;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use mas_data_model::{
|
||||
};
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
pagination::Node,
|
||||
user::{UserEmailFilter, UserEmailRepository},
|
||||
};
|
||||
use rand::RngCore;
|
||||
@@ -51,6 +52,12 @@ struct UserEmailLookup {
|
||||
created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for UserEmailLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.user_email_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UserEmailLookup> for UserEmail {
|
||||
fn from(e: UserEmailLookup) -> UserEmail {
|
||||
UserEmail {
|
||||
|
||||
@@ -61,7 +61,9 @@ mod priv_ {
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use mas_storage::pagination::Node;
|
||||
use sea_query::enum_def;
|
||||
use ulid::Ulid;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||
@@ -75,6 +77,12 @@ mod priv_ {
|
||||
pub(super) can_request_admin: bool,
|
||||
pub(super) is_guest: bool,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for UserLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.user_id.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use priv_::{UserLookup, UserLookupIden};
|
||||
|
||||
@@ -8,6 +8,7 @@ use chrono::{DateTime, Utc};
|
||||
use mas_data_model::{Clock, UserRegistrationToken};
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
pagination::Node,
|
||||
user::{UserRegistrationTokenFilter, UserRegistrationTokenRepository},
|
||||
};
|
||||
use rand::RngCore;
|
||||
@@ -53,6 +54,12 @@ struct UserRegistrationTokenLookup {
|
||||
revoked_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for UserRegistrationTokenLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.user_registration_token_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Filter for UserRegistrationTokenFilter {
|
||||
fn generate_condition(&self, _has_joins: bool) -> impl sea_query::IntoCondition {
|
||||
sea_query::Condition::all()
|
||||
@@ -230,7 +237,7 @@ impl UserRegistrationTokenRepository for PgUserRegistrationTokenRepository<'_> {
|
||||
filter: UserRegistrationTokenFilter,
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<UserRegistrationToken>, Self::Error> {
|
||||
let (sql, values) = Query::select()
|
||||
let (sql, arguments) = Query::select()
|
||||
.expr_as(
|
||||
Expr::col((
|
||||
UserRegistrationTokens::Table,
|
||||
@@ -295,15 +302,14 @@ impl UserRegistrationTokenRepository for PgUserRegistrationTokenRepository<'_> {
|
||||
)
|
||||
.build_sqlx(PostgresQueryBuilder);
|
||||
|
||||
let tokens = sqlx::query_as_with::<_, UserRegistrationTokenLookup, _>(&sql, values)
|
||||
let edges: Vec<UserRegistrationTokenLookup> = sqlx::query_as_with(&sql, arguments)
|
||||
.traced()
|
||||
.fetch_all(&mut *self.conn)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
.await?;
|
||||
|
||||
let page = pagination.process(tokens);
|
||||
let page = pagination
|
||||
.process(edges)
|
||||
.try_map(UserRegistrationToken::try_from)?;
|
||||
|
||||
Ok(page)
|
||||
}
|
||||
@@ -705,7 +711,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(page.edges.iter().any(|t| t.id == unrevoked_token.id));
|
||||
assert!(page.edges.iter().any(|t| t.node.id == unrevoked_token.id));
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||
@@ -867,7 +873,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(page.edges.len(), 1);
|
||||
assert_eq!(page.edges[0].id, token2.id);
|
||||
assert_eq!(page.edges[0].node.id, token2.id);
|
||||
|
||||
// Test unused filter
|
||||
let unused_filter = UserRegistrationTokenFilter::new(clock.now()).with_been_used(false);
|
||||
@@ -886,7 +892,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(page.edges.len(), 1);
|
||||
assert_eq!(page.edges[0].id, token3.id);
|
||||
assert_eq!(page.edges[0].node.id, token3.id);
|
||||
|
||||
let not_expired_filter = UserRegistrationTokenFilter::new(clock.now()).with_expired(false);
|
||||
let page = repo
|
||||
@@ -904,7 +910,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(page.edges.len(), 1);
|
||||
assert_eq!(page.edges[0].id, token4.id);
|
||||
assert_eq!(page.edges[0].node.id, token4.id);
|
||||
|
||||
let not_revoked_filter = UserRegistrationTokenFilter::new(clock.now()).with_revoked(false);
|
||||
let page = repo
|
||||
@@ -941,7 +947,7 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(page.edges.len(), 1);
|
||||
assert_eq!(page.edges[0].id, token4.id);
|
||||
assert_eq!(page.edges[0].node.id, token4.id);
|
||||
|
||||
// Test pagination
|
||||
let page = repo
|
||||
|
||||
@@ -14,6 +14,7 @@ use mas_data_model::{
|
||||
};
|
||||
use mas_storage::{
|
||||
Page, Pagination,
|
||||
pagination::Node,
|
||||
user::{BrowserSessionFilter, BrowserSessionRepository},
|
||||
};
|
||||
use rand::RngCore;
|
||||
@@ -64,6 +65,12 @@ struct SessionLookup {
|
||||
user_is_guest: bool,
|
||||
}
|
||||
|
||||
impl Node<Ulid> for SessionLookup {
|
||||
fn cursor(&self) -> Ulid {
|
||||
self.user_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SessionLookup> for BrowserSession {
|
||||
type Error = DatabaseInconsistencyError;
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ async fn test_user_repo(pool: PgPool) {
|
||||
// Check the list method
|
||||
let list = repo.user().list(all, Pagination::first(10)).await.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0].id, user.id);
|
||||
assert_eq!(list.edges[0].node.id, user.id);
|
||||
|
||||
let list = repo
|
||||
.user()
|
||||
@@ -205,7 +205,7 @@ async fn test_user_repo(pool: PgPool) {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0].id, user.id);
|
||||
assert_eq!(list.edges[0].node.id, user.id);
|
||||
|
||||
let list = repo
|
||||
.user()
|
||||
@@ -227,7 +227,7 @@ async fn test_user_repo(pool: PgPool) {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(list.edges.len(), 1);
|
||||
assert_eq!(list.edges[0].id, user.id);
|
||||
assert_eq!(list.edges[0].node.id, user.id);
|
||||
|
||||
repo.save().await.unwrap();
|
||||
}
|
||||
@@ -348,7 +348,7 @@ async fn test_user_email_repo(pool: PgPool) {
|
||||
.unwrap();
|
||||
assert!(!emails.has_next_page);
|
||||
assert_eq!(emails.edges.len(), 1);
|
||||
assert_eq!(emails.edges[0], user_email);
|
||||
assert_eq!(emails.edges[0].node, user_email);
|
||||
|
||||
// Listing emails from the email address should work
|
||||
let emails = repo
|
||||
@@ -358,7 +358,7 @@ async fn test_user_email_repo(pool: PgPool) {
|
||||
.unwrap();
|
||||
assert!(!emails.has_next_page);
|
||||
assert_eq!(emails.edges.len(), 1);
|
||||
assert_eq!(emails.edges[0], user_email);
|
||||
assert_eq!(emails.edges[0].node, user_email);
|
||||
|
||||
// Filtering on another email should not return anything
|
||||
let emails = repo
|
||||
@@ -648,7 +648,7 @@ async fn test_user_session(pool: PgPool) {
|
||||
.unwrap();
|
||||
assert!(!session_list.has_next_page);
|
||||
assert_eq!(session_list.edges.len(), 1);
|
||||
assert_eq!(session_list.edges[0], session);
|
||||
assert_eq!(session_list.edges[0].node, session);
|
||||
|
||||
let session_lookup = repo
|
||||
.browser_session()
|
||||
@@ -809,7 +809,7 @@ async fn test_user_session(pool: PgPool) {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(page.edges.len(), 1);
|
||||
assert_eq!(page.edges[0].id, session.id);
|
||||
assert_eq!(page.edges[0].node.id, session.id);
|
||||
|
||||
// Try counting
|
||||
assert_eq!(repo.browser_session().count(filter).await.unwrap(), 1);
|
||||
|
||||
@@ -16,12 +16,12 @@ pub struct InvalidPagination;
|
||||
|
||||
/// Pagination parameters
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Pagination {
|
||||
pub struct Pagination<Cursor = Ulid> {
|
||||
/// The cursor to start from
|
||||
pub before: Option<Ulid>,
|
||||
pub before: Option<Cursor>,
|
||||
|
||||
/// The cursor to end at
|
||||
pub after: Option<Ulid>,
|
||||
pub after: Option<Cursor>,
|
||||
|
||||
/// The maximum number of items to return
|
||||
pub count: usize,
|
||||
@@ -40,16 +40,22 @@ pub enum PaginationDirection {
|
||||
Backward,
|
||||
}
|
||||
|
||||
impl Pagination {
|
||||
/// A node in a page, with a cursor
|
||||
pub trait Node<C = Ulid> {
|
||||
/// The cursor of that particular node
|
||||
fn cursor(&self) -> C;
|
||||
}
|
||||
|
||||
impl<C> Pagination<C> {
|
||||
/// Creates a new [`Pagination`] from user-provided parameters.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Either `first` or `last` must be provided, else this function will
|
||||
/// return an [`InvalidPagination`] error.
|
||||
pub const fn try_new(
|
||||
before: Option<Ulid>,
|
||||
after: Option<Ulid>,
|
||||
pub fn try_new(
|
||||
before: Option<C>,
|
||||
after: Option<C>,
|
||||
first: Option<usize>,
|
||||
last: Option<usize>,
|
||||
) -> Result<Self, InvalidPagination> {
|
||||
@@ -91,49 +97,57 @@ impl Pagination {
|
||||
|
||||
/// Get items before the given cursor
|
||||
#[must_use]
|
||||
pub const fn before(mut self, id: Ulid) -> Self {
|
||||
self.before = Some(id);
|
||||
pub fn before(mut self, cursor: C) -> Self {
|
||||
self.before = Some(cursor);
|
||||
self
|
||||
}
|
||||
|
||||
/// Clear the before cursor
|
||||
#[must_use]
|
||||
pub const fn clear_before(mut self) -> Self {
|
||||
pub fn clear_before(mut self) -> Self {
|
||||
self.before = None;
|
||||
self
|
||||
}
|
||||
|
||||
/// Get items after the given cursor
|
||||
#[must_use]
|
||||
pub const fn after(mut self, id: Ulid) -> Self {
|
||||
self.after = Some(id);
|
||||
pub fn after(mut self, cursor: C) -> Self {
|
||||
self.after = Some(cursor);
|
||||
self
|
||||
}
|
||||
|
||||
/// Clear the after cursor
|
||||
#[must_use]
|
||||
pub const fn clear_after(mut self) -> Self {
|
||||
pub fn clear_after(mut self) -> Self {
|
||||
self.after = None;
|
||||
self
|
||||
}
|
||||
|
||||
/// Process a page returned by a paginated query
|
||||
#[must_use]
|
||||
pub fn process<T>(&self, mut edges: Vec<T>) -> Page<T> {
|
||||
let is_full = edges.len() == (self.count + 1);
|
||||
pub fn process<T: Node<C>>(&self, mut nodes: Vec<T>) -> Page<T, C> {
|
||||
let is_full = nodes.len() == (self.count + 1);
|
||||
if is_full {
|
||||
edges.pop();
|
||||
nodes.pop();
|
||||
}
|
||||
|
||||
let (has_previous_page, has_next_page) = match self.direction {
|
||||
PaginationDirection::Forward => (false, is_full),
|
||||
PaginationDirection::Backward => {
|
||||
// 6. If the last argument is provided, I reverse the order of the results
|
||||
edges.reverse();
|
||||
nodes.reverse();
|
||||
(is_full, false)
|
||||
}
|
||||
};
|
||||
|
||||
let edges = nodes
|
||||
.into_iter()
|
||||
.map(|node| Edge {
|
||||
cursor: node.cursor(),
|
||||
node,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Page {
|
||||
has_next_page,
|
||||
has_previous_page,
|
||||
@@ -142,9 +156,18 @@ impl Pagination {
|
||||
}
|
||||
}
|
||||
|
||||
/// An edge in a paginated result
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Edge<T, C = Ulid> {
|
||||
/// The cursor of the edge
|
||||
pub cursor: C,
|
||||
/// The node of the edge
|
||||
pub node: T,
|
||||
}
|
||||
|
||||
/// A page of results returned by a paginated query
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Page<T> {
|
||||
pub struct Page<T, C = Ulid> {
|
||||
/// When paginating forwards, this is true if there are more items after
|
||||
pub has_next_page: bool,
|
||||
|
||||
@@ -152,21 +175,28 @@ pub struct Page<T> {
|
||||
pub has_previous_page: bool,
|
||||
|
||||
/// The items in the page
|
||||
pub edges: Vec<T>,
|
||||
pub edges: Vec<Edge<T, C>>,
|
||||
}
|
||||
|
||||
impl<T> Page<T> {
|
||||
impl<T, C> Page<T, C> {
|
||||
/// Map the items in this page with the given function
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `f`: The function to map the items with
|
||||
#[must_use]
|
||||
pub fn map<F, T2>(self, f: F) -> Page<T2>
|
||||
pub fn map<F, T2>(self, mut f: F) -> Page<T2, C>
|
||||
where
|
||||
F: FnMut(T) -> T2,
|
||||
{
|
||||
let edges = self.edges.into_iter().map(f).collect();
|
||||
let edges = self
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(|edge| Edge {
|
||||
cursor: edge.cursor,
|
||||
node: f(edge.node),
|
||||
})
|
||||
.collect();
|
||||
Page {
|
||||
has_next_page: self.has_next_page,
|
||||
has_previous_page: self.has_previous_page,
|
||||
@@ -183,11 +213,21 @@ impl<T> Page<T> {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns the first error encountered while mapping the items
|
||||
pub fn try_map<F, E, T2>(self, f: F) -> Result<Page<T2>, E>
|
||||
pub fn try_map<F, E, T2>(self, mut f: F) -> Result<Page<T2, C>, E>
|
||||
where
|
||||
F: FnMut(T) -> Result<T2, E>,
|
||||
{
|
||||
let edges: Result<Vec<T2>, E> = self.edges.into_iter().map(f).collect();
|
||||
let edges: Result<Vec<Edge<T2, C>>, E> = self
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(|edge| {
|
||||
Ok(Edge {
|
||||
cursor: edge.cursor,
|
||||
node: f(edge.node)?,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Page {
|
||||
has_next_page: self.has_next_page,
|
||||
has_previous_page: self.has_previous_page,
|
||||
|
||||
@@ -384,7 +384,7 @@ impl ExpireInactiveOAuthSessionsJob {
|
||||
let last_edge = page.edges.last()?;
|
||||
Some(Self {
|
||||
threshold: self.threshold,
|
||||
after: Some(last_edge.id),
|
||||
after: Some(last_edge.cursor),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -441,7 +441,7 @@ impl ExpireInactiveCompatSessionsJob {
|
||||
let last_edge = page.edges.last()?;
|
||||
Some(Self {
|
||||
threshold: self.threshold,
|
||||
after: Some(last_edge.id),
|
||||
after: Some(last_edge.cursor),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -498,7 +498,7 @@ impl ExpireInactiveUserSessionsJob {
|
||||
let last_edge = page.edges.last()?;
|
||||
Some(Self {
|
||||
threshold: self.threshold,
|
||||
after: Some(last_edge.id),
|
||||
after: Some(last_edge.cursor),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,11 +203,12 @@ impl RunnableJob for SyncDevicesJob {
|
||||
.await
|
||||
.map_err(JobError::retry)?;
|
||||
|
||||
for (compat_session, _) in page.edges {
|
||||
for edge in page.edges {
|
||||
let (compat_session, _) = edge.node;
|
||||
if let Some(ref device) = compat_session.device {
|
||||
devices.insert(device.as_str().to_owned());
|
||||
}
|
||||
cursor = cursor.after(compat_session.id);
|
||||
cursor = cursor.after(edge.cursor);
|
||||
}
|
||||
|
||||
if !page.has_next_page {
|
||||
@@ -227,14 +228,14 @@ impl RunnableJob for SyncDevicesJob {
|
||||
.await
|
||||
.map_err(JobError::retry)?;
|
||||
|
||||
for oauth2_session in page.edges {
|
||||
for scope in &*oauth2_session.scope {
|
||||
for edge in page.edges {
|
||||
for scope in &*edge.node.scope {
|
||||
if let Some(device) = Device::from_scope_token(scope) {
|
||||
devices.insert(device.as_str().to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
cursor = cursor.after(oauth2_session.id);
|
||||
cursor = cursor.after(edge.cursor);
|
||||
}
|
||||
|
||||
if !page.has_next_page {
|
||||
|
||||
@@ -70,26 +70,18 @@ impl RunnableJob for SendAccountRecoveryEmailsJob {
|
||||
.await
|
||||
.map_err(JobError::retry)?;
|
||||
|
||||
for email in page.edges {
|
||||
for edge in page.edges {
|
||||
let ticket = Alphanumeric.sample_string(&mut rng, 32);
|
||||
|
||||
let ticket = repo
|
||||
.user_recovery()
|
||||
.add_ticket(&mut rng, clock, &session, &email, ticket)
|
||||
.add_ticket(&mut rng, clock, &session, &edge.node, ticket)
|
||||
.await
|
||||
.map_err(JobError::retry)?;
|
||||
|
||||
let user_email = repo
|
||||
.user_email()
|
||||
.lookup(email.id)
|
||||
.await
|
||||
.map_err(JobError::retry)?
|
||||
.context("User email not found")
|
||||
.map_err(JobError::fail)?;
|
||||
|
||||
let user = repo
|
||||
.user()
|
||||
.lookup(user_email.user_id)
|
||||
.lookup(edge.node.user_id)
|
||||
.await
|
||||
.map_err(JobError::retry)?
|
||||
.context("User not found")
|
||||
@@ -97,7 +89,7 @@ impl RunnableJob for SendAccountRecoveryEmailsJob {
|
||||
|
||||
let url = url_builder.account_recovery_link(ticket.ticket);
|
||||
|
||||
let address: Address = user_email.email.parse().map_err(JobError::fail)?;
|
||||
let address: Address = edge.node.email.parse().map_err(JobError::fail)?;
|
||||
let mailbox = Mailbox::new(Some(user.username.clone()), address);
|
||||
|
||||
info!("Sending recovery email to {}", mailbox);
|
||||
@@ -112,7 +104,7 @@ impl RunnableJob for SendAccountRecoveryEmailsJob {
|
||||
);
|
||||
}
|
||||
|
||||
cursor = cursor.after(email.id);
|
||||
cursor = cursor.after(edge.cursor);
|
||||
}
|
||||
|
||||
if !page.has_next_page {
|
||||
|
||||
@@ -110,7 +110,7 @@ impl RunnableJob for ExpireInactiveOAuthSessionsJob {
|
||||
}
|
||||
|
||||
for edge in page.edges {
|
||||
if let Some(user_id) = edge.user_id {
|
||||
if let Some(user_id) = edge.node.user_id {
|
||||
let inserted = users_synced.insert(user_id);
|
||||
if inserted {
|
||||
tracing::info!(user.id = %user_id, "Scheduling devices sync for user");
|
||||
@@ -128,7 +128,7 @@ impl RunnableJob for ExpireInactiveOAuthSessionsJob {
|
||||
}
|
||||
|
||||
repo.oauth2_session()
|
||||
.finish(clock, edge)
|
||||
.finish(clock, edge.node)
|
||||
.await
|
||||
.map_err(JobError::retry)?;
|
||||
}
|
||||
@@ -174,14 +174,14 @@ impl RunnableJob for ExpireInactiveCompatSessionsJob {
|
||||
}
|
||||
|
||||
for edge in page.edges {
|
||||
let inserted = users_synced.insert(edge.user_id);
|
||||
let inserted = users_synced.insert(edge.node.user_id);
|
||||
if inserted {
|
||||
tracing::info!(user.id = %edge.user_id, "Scheduling devices sync for user");
|
||||
tracing::info!(user.id = %edge.node.user_id, "Scheduling devices sync for user");
|
||||
repo.queue_job()
|
||||
.schedule_job_later(
|
||||
&mut rng,
|
||||
clock,
|
||||
SyncDevicesJob::new_for_id(edge.user_id),
|
||||
SyncDevicesJob::new_for_id(edge.node.user_id),
|
||||
clock.now() + delay,
|
||||
)
|
||||
.await
|
||||
@@ -190,7 +190,7 @@ impl RunnableJob for ExpireInactiveCompatSessionsJob {
|
||||
}
|
||||
|
||||
repo.compat_session()
|
||||
.finish(clock, edge)
|
||||
.finish(clock, edge.node)
|
||||
.await
|
||||
.map_err(JobError::retry)?;
|
||||
}
|
||||
@@ -230,7 +230,7 @@ impl RunnableJob for ExpireInactiveUserSessionsJob {
|
||||
|
||||
for edge in page.edges {
|
||||
repo.browser_session()
|
||||
.finish(clock, edge)
|
||||
.finish(clock, edge.node)
|
||||
.await
|
||||
.map_err(JobError::retry)?;
|
||||
}
|
||||
|
||||
@@ -182,6 +182,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -201,6 +206,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/02081040G2081040G2081040G2"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "02081040G2081040G2081040G2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -220,6 +230,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/compat-sessions/030C1G60R30C1G60R30C1G60R3"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "030C1G60R30C1G60R30C1G60R3"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -495,6 +510,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -514,6 +534,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions/02081040G2081040G2081040G2"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "02081040G2081040G2081040G2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -533,6 +558,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/oauth2-sessions/030C1G60R30C1G60R30C1G60R3"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "030C1G60R30C1G60R30C1G60R3"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -997,6 +1027,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1012,6 +1047,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/02081040G2081040G2081040G2"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "02081040G2081040G2081040G2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1027,6 +1067,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/users/030C1G60R30C1G60R30C1G60R3"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "030C1G60R30C1G60R30C1G60R3"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1842,6 +1887,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-emails/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -2201,6 +2251,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2216,6 +2271,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/02081040G2081040G2081040G2"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "02081040G2081040G2081040G2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2231,6 +2291,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-sessions/030C1G60R30C1G60R30C1G60R3"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "030C1G60R30C1G60R30C1G60R3"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -2474,6 +2539,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2491,6 +2561,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/user-registration-tokens/02081040G2081040G2081040G2"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "02081040G2081040G2081040G2"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -3018,6 +3093,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3032,6 +3112,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/02081040G2081040G2081040G2"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "02081040G2081040G2081040G2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3046,6 +3131,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-links/030C1G60R30C1G60R30C1G60R3"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "030C1G60R30C1G60R30C1G60R3"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -3404,6 +3494,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/01040G2081040G2081040G2081"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "01040G2081040G2081040G2081"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3418,6 +3513,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/02081040G2081040G2081040G2"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "02081040G2081040G2081040G2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3432,6 +3532,11 @@
|
||||
},
|
||||
"links": {
|
||||
"self": "/api/admin/v1/upstream-oauth-providers/030C1G60R30C1G60R30C1G60R3"
|
||||
},
|
||||
"meta": {
|
||||
"page": {
|
||||
"cursor": "030C1G60R30C1G60R30C1G60R3"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -3684,6 +3789,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -3702,6 +3808,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3790,6 +3900,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"SingleResourceMeta": {
|
||||
"description": "Metadata associated with a resource",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"page": {
|
||||
"description": "Information about the pagination of the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMetaPage",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"SingleResourceMetaPage": {
|
||||
"description": "Pagination metadata for a resource",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"cursor"
|
||||
],
|
||||
"properties": {
|
||||
"cursor": {
|
||||
"description": "The cursor of this resource in the paginated result",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PaginationLinks": {
|
||||
"description": "Related links",
|
||||
"type": "object",
|
||||
@@ -3965,6 +4099,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -3983,6 +4118,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4105,6 +4244,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -4123,6 +4263,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4210,6 +4354,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -4228,6 +4373,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4411,6 +4560,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -4429,6 +4579,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4546,6 +4700,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -4564,6 +4719,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4683,6 +4842,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -4701,6 +4861,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4872,6 +5036,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -4890,6 +5055,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5014,6 +5183,7 @@
|
||||
"attributes",
|
||||
"id",
|
||||
"links",
|
||||
"meta",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@@ -5032,6 +5202,10 @@
|
||||
"links": {
|
||||
"description": "Related links",
|
||||
"$ref": "#/components/schemas/SelfLinks"
|
||||
},
|
||||
"meta": {
|
||||
"description": "Metadata about the resource",
|
||||
"$ref": "#/components/schemas/SingleResourceMeta"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
1516
frontend/package-lock.json
generated
1516
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -18,11 +18,11 @@
|
||||
"knip": "knip"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/inconsolata": "^5.2.7",
|
||||
"@fontsource/inter": "^5.2.7",
|
||||
"@fontsource/inconsolata": "^5.2.8",
|
||||
"@fontsource/inter": "^5.2.8",
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@tanstack/react-query": "^5.89.0",
|
||||
"@tanstack/react-query": "^5.90.2",
|
||||
"@tanstack/react-router": "^1.131.44",
|
||||
"@vector-im/compound-design-tokens": "6.0.0",
|
||||
"@vector-im/compound-web": "^8.2.4",
|
||||
@@ -43,22 +43,22 @@
|
||||
"@browser-logos/chrome": "^2.0.0",
|
||||
"@browser-logos/firefox": "^3.0.10",
|
||||
"@browser-logos/safari": "^2.1.0",
|
||||
"@graphql-codegen/cli": "^5.0.7",
|
||||
"@graphql-codegen/client-preset": "^4.8.3",
|
||||
"@graphql-codegen/cli": "^6.0.0",
|
||||
"@graphql-codegen/client-preset": "^5.0.2",
|
||||
"@graphql-codegen/typescript-msw": "^3.0.1",
|
||||
"@storybook/addon-docs": "^9.1.6",
|
||||
"@storybook/react-vite": "^9.1.6",
|
||||
"@tanstack/react-query-devtools": "^5.89.0",
|
||||
"@storybook/addon-docs": "^9.1.8",
|
||||
"@storybook/react-vite": "^9.1.8",
|
||||
"@tanstack/react-query-devtools": "^5.90.2",
|
||||
"@tanstack/react-router-devtools": "^1.131.44",
|
||||
"@tanstack/router-plugin": "^1.131.44",
|
||||
"@testing-library/jest-dom": "^6.8.0",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/node": "^24.5.0",
|
||||
"@types/react": "19.1.13",
|
||||
"@types/node": "^24.6.0",
|
||||
"@types/react": "19.1.16",
|
||||
"@types/react-dom": "19.1.9",
|
||||
"@types/swagger-ui-dist": "^3.30.6",
|
||||
"@vitejs/plugin-react": "^5.0.3",
|
||||
"@vitejs/plugin-react": "^5.0.4",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"browserslist-to-esbuild": "^2.1.1",
|
||||
@@ -76,7 +76,7 @@
|
||||
"storybook-react-i18next": "4.0.11",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "7.1.6",
|
||||
"vite": "7.1.7",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-graphql-codegen": "^3.7.0",
|
||||
"vite-plugin-manifest-sri": "^0.2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { DocumentTypeDecoration } from '@graphql-typed-document-node/core';
|
||||
import { graphql, type GraphQLResponseResolver, type RequestHandlerOptions } from 'msw'
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
export type InputMaybe<T> = T | null | undefined;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
@@ -1838,10 +1838,13 @@ export type UserEmailListQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UserEmailListQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | { __typename: 'User', emails: { __typename?: 'UserEmailConnection', totalCount: number, edges: Array<{ __typename?: 'UserEmailEdge', cursor: string, node: (
|
||||
{ __typename?: 'UserEmail' }
|
||||
& { ' $fragmentRefs'?: { 'UserEmail_EmailFragment': UserEmail_EmailFragment } }
|
||||
) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } };
|
||||
export type UserEmailListQuery = { __typename?: 'Query', viewer:
|
||||
| { __typename: 'Anonymous' }
|
||||
| { __typename: 'User', emails: { __typename?: 'UserEmailConnection', totalCount: number, edges: Array<{ __typename?: 'UserEmailEdge', cursor: string, node: (
|
||||
{ __typename?: 'UserEmail' }
|
||||
& { ' $fragmentRefs'?: { 'UserEmail_EmailFragment': UserEmail_EmailFragment } }
|
||||
) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } }
|
||||
};
|
||||
|
||||
export type UserEmailList_UserFragment = { __typename?: 'User', hasPassword: boolean } & { ' $fragmentName'?: 'UserEmailList_UserFragment' };
|
||||
|
||||
@@ -1852,10 +1855,14 @@ export type BrowserSessionsOverview_UserFragment = { __typename?: 'User', id: st
|
||||
export type UserProfileQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type UserProfileQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: (
|
||||
{ __typename?: 'User', hasPassword: boolean, emails: { __typename?: 'UserEmailConnection', totalCount: number } }
|
||||
& { ' $fragmentRefs'?: { 'AddEmailForm_UserFragment': AddEmailForm_UserFragment;'UserEmailList_UserFragment': UserEmailList_UserFragment;'AccountDeleteButton_UserFragment': AccountDeleteButton_UserFragment } }
|
||||
) } | { __typename: 'Oauth2Session' }, siteConfig: (
|
||||
export type UserProfileQuery = { __typename?: 'Query', viewerSession:
|
||||
| { __typename: 'Anonymous' }
|
||||
| { __typename: 'BrowserSession', id: string, user: (
|
||||
{ __typename?: 'User', hasPassword: boolean, emails: { __typename?: 'UserEmailConnection', totalCount: number } }
|
||||
& { ' $fragmentRefs'?: { 'AddEmailForm_UserFragment': AddEmailForm_UserFragment;'UserEmailList_UserFragment': UserEmailList_UserFragment;'AccountDeleteButton_UserFragment': AccountDeleteButton_UserFragment } }
|
||||
) }
|
||||
| { __typename: 'Oauth2Session' }
|
||||
, siteConfig: (
|
||||
{ __typename?: 'SiteConfig', emailChangeAllowed: boolean, passwordLoginEnabled: boolean, accountDeactivationAllowed: boolean }
|
||||
& { ' $fragmentRefs'?: { 'AddEmailForm_SiteConfigFragment': AddEmailForm_SiteConfigFragment;'UserEmailList_SiteConfigFragment': UserEmailList_SiteConfigFragment;'PasswordChange_SiteConfigFragment': PasswordChange_SiteConfigFragment;'AccountDeleteButton_SiteConfigFragment': AccountDeleteButton_SiteConfigFragment } }
|
||||
) };
|
||||
@@ -1874,18 +1881,25 @@ export type BrowserSessionListQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type BrowserSessionListQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: { __typename?: 'User', id: string, browserSessions: { __typename?: 'BrowserSessionConnection', totalCount: number, edges: Array<{ __typename?: 'BrowserSessionEdge', cursor: string, node: (
|
||||
{ __typename?: 'BrowserSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSession_SessionFragment': BrowserSession_SessionFragment } }
|
||||
) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } } | { __typename: 'Oauth2Session' } };
|
||||
export type BrowserSessionListQuery = { __typename?: 'Query', viewerSession:
|
||||
| { __typename: 'Anonymous' }
|
||||
| { __typename: 'BrowserSession', id: string, user: { __typename?: 'User', id: string, browserSessions: { __typename?: 'BrowserSessionConnection', totalCount: number, edges: Array<{ __typename?: 'BrowserSessionEdge', cursor: string, node: (
|
||||
{ __typename?: 'BrowserSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSession_SessionFragment': BrowserSession_SessionFragment } }
|
||||
) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } }
|
||||
| { __typename: 'Oauth2Session' }
|
||||
};
|
||||
|
||||
export type SessionsOverviewQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type SessionsOverviewQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | (
|
||||
{ __typename: 'User', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSessionsOverview_UserFragment': BrowserSessionsOverview_UserFragment } }
|
||||
) };
|
||||
export type SessionsOverviewQuery = { __typename?: 'Query', viewer:
|
||||
| { __typename: 'Anonymous' }
|
||||
| (
|
||||
{ __typename: 'User', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSessionsOverview_UserFragment': BrowserSessionsOverview_UserFragment } }
|
||||
)
|
||||
};
|
||||
|
||||
export type AppSessionsListQueryVariables = Exact<{
|
||||
before?: InputMaybe<Scalars['String']['input']>;
|
||||
@@ -1896,21 +1910,30 @@ export type AppSessionsListQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type AppSessionsListQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | { __typename: 'User', id: string, appSessions: { __typename?: 'AppSessionConnection', totalCount: number, edges: Array<{ __typename?: 'AppSessionEdge', cursor: string, node: (
|
||||
{ __typename: 'CompatSession' }
|
||||
& { ' $fragmentRefs'?: { 'CompatSession_SessionFragment': CompatSession_SessionFragment } }
|
||||
) | (
|
||||
{ __typename: 'Oauth2Session' }
|
||||
& { ' $fragmentRefs'?: { 'OAuth2Session_SessionFragment': OAuth2Session_SessionFragment } }
|
||||
) }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } } };
|
||||
export type AppSessionsListQuery = { __typename?: 'Query', viewer:
|
||||
| { __typename: 'Anonymous' }
|
||||
| { __typename: 'User', id: string, appSessions: { __typename?: 'AppSessionConnection', totalCount: number, edges: Array<{ __typename?: 'AppSessionEdge', cursor: string, node:
|
||||
| (
|
||||
{ __typename: 'CompatSession' }
|
||||
& { ' $fragmentRefs'?: { 'CompatSession_SessionFragment': CompatSession_SessionFragment } }
|
||||
)
|
||||
| (
|
||||
{ __typename: 'Oauth2Session' }
|
||||
& { ' $fragmentRefs'?: { 'OAuth2Session_SessionFragment': OAuth2Session_SessionFragment } }
|
||||
)
|
||||
}>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }
|
||||
};
|
||||
|
||||
export type CurrentUserGreetingQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type CurrentUserGreetingQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | (
|
||||
{ __typename: 'User' }
|
||||
& { ' $fragmentRefs'?: { 'UserGreeting_UserFragment': UserGreeting_UserFragment } }
|
||||
), siteConfig: (
|
||||
export type CurrentUserGreetingQuery = { __typename?: 'Query', viewer:
|
||||
| { __typename: 'Anonymous' }
|
||||
| (
|
||||
{ __typename: 'User' }
|
||||
& { ' $fragmentRefs'?: { 'UserGreeting_UserFragment': UserGreeting_UserFragment } }
|
||||
)
|
||||
, siteConfig: (
|
||||
{ __typename?: 'SiteConfig', planManagementIframeUri?: string | null }
|
||||
& { ' $fragmentRefs'?: { 'UserGreeting_SiteConfigFragment': UserGreeting_SiteConfigFragment } }
|
||||
) };
|
||||
@@ -1928,7 +1951,10 @@ export type OAuth2ClientQuery = { __typename?: 'Query', oauth2Client?: (
|
||||
export type CurrentViewerQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type CurrentViewerQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous', id: string } | { __typename: 'User', id: string } };
|
||||
export type CurrentViewerQuery = { __typename?: 'Query', viewer:
|
||||
| { __typename: 'Anonymous', id: string }
|
||||
| { __typename: 'User', id: string }
|
||||
};
|
||||
|
||||
export type DeviceRedirectQueryVariables = Exact<{
|
||||
deviceId: Scalars['String']['input'];
|
||||
@@ -1936,7 +1962,10 @@ export type DeviceRedirectQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type DeviceRedirectQuery = { __typename?: 'Query', session?: { __typename: 'CompatSession', id: string } | { __typename: 'Oauth2Session', id: string } | null };
|
||||
export type DeviceRedirectQuery = { __typename?: 'Query', session?:
|
||||
| { __typename: 'CompatSession', id: string }
|
||||
| { __typename: 'Oauth2Session', id: string }
|
||||
| null };
|
||||
|
||||
export type VerifyEmailQueryVariables = Exact<{
|
||||
id: Scalars['ID']['input'];
|
||||
@@ -1973,7 +2002,10 @@ export type ChangePasswordMutation = { __typename?: 'Mutation', setPassword: { _
|
||||
export type PasswordChangeQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type PasswordChangeQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous', id: string } | { __typename: 'User', id: string }, siteConfig: (
|
||||
export type PasswordChangeQuery = { __typename?: 'Query', viewer:
|
||||
| { __typename: 'Anonymous', id: string }
|
||||
| { __typename: 'User', id: string }
|
||||
, siteConfig: (
|
||||
{ __typename?: 'SiteConfig' }
|
||||
& { ' $fragmentRefs'?: { 'PasswordCreationDoubleInput_SiteConfigFragment': PasswordCreationDoubleInput_SiteConfigFragment } }
|
||||
) };
|
||||
@@ -2025,16 +2057,35 @@ export type SessionDetailQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type SessionDetailQuery = { __typename?: 'Query', viewerSession: { __typename?: 'Anonymous', id: string } | { __typename?: 'BrowserSession', id: string } | { __typename?: 'Oauth2Session', id: string }, node?: { __typename: 'Anonymous', id: string } | { __typename: 'Authentication', id: string } | (
|
||||
{ __typename: 'BrowserSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSession_DetailFragment': BrowserSession_DetailFragment } }
|
||||
) | (
|
||||
{ __typename: 'CompatSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'CompatSession_DetailFragment': CompatSession_DetailFragment } }
|
||||
) | { __typename: 'CompatSsoLogin', id: string } | { __typename: 'Oauth2Client', id: string } | (
|
||||
{ __typename: 'Oauth2Session', id: string }
|
||||
& { ' $fragmentRefs'?: { 'OAuth2Session_DetailFragment': OAuth2Session_DetailFragment } }
|
||||
) | { __typename: 'SiteConfig', id: string } | { __typename: 'UpstreamOAuth2Link', id: string } | { __typename: 'UpstreamOAuth2Provider', id: string } | { __typename: 'User', id: string } | { __typename: 'UserEmail', id: string } | { __typename: 'UserEmailAuthentication', id: string } | { __typename: 'UserRecoveryTicket', id: string } | null };
|
||||
export type SessionDetailQuery = { __typename?: 'Query', viewerSession:
|
||||
| { __typename?: 'Anonymous', id: string }
|
||||
| { __typename?: 'BrowserSession', id: string }
|
||||
| { __typename?: 'Oauth2Session', id: string }
|
||||
, node?:
|
||||
| { __typename: 'Anonymous', id: string }
|
||||
| { __typename: 'Authentication', id: string }
|
||||
| (
|
||||
{ __typename: 'BrowserSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'BrowserSession_DetailFragment': BrowserSession_DetailFragment } }
|
||||
)
|
||||
| (
|
||||
{ __typename: 'CompatSession', id: string }
|
||||
& { ' $fragmentRefs'?: { 'CompatSession_DetailFragment': CompatSession_DetailFragment } }
|
||||
)
|
||||
| { __typename: 'CompatSsoLogin', id: string }
|
||||
| { __typename: 'Oauth2Client', id: string }
|
||||
| (
|
||||
{ __typename: 'Oauth2Session', id: string }
|
||||
& { ' $fragmentRefs'?: { 'OAuth2Session_DetailFragment': OAuth2Session_DetailFragment } }
|
||||
)
|
||||
| { __typename: 'SiteConfig', id: string }
|
||||
| { __typename: 'UpstreamOAuth2Link', id: string }
|
||||
| { __typename: 'UpstreamOAuth2Provider', id: string }
|
||||
| { __typename: 'User', id: string }
|
||||
| { __typename: 'UserEmail', id: string }
|
||||
| { __typename: 'UserEmailAuthentication', id: string }
|
||||
| { __typename: 'UserRecoveryTicket', id: string }
|
||||
| null };
|
||||
|
||||
export class TypedDocumentString<TResult, TVariables>
|
||||
extends String
|
||||
|
||||
Reference in New Issue
Block a user