Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: allow querying all offers and all credentials of issuer #121

Merged
merged 12 commits into from
Oct 3, 2024
104 changes: 104 additions & 0 deletions agent_api_rest/postman/ssi-agent.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,58 @@
},
"response": []
},
{
"name": "all_credentials",
"event": [
{
"listen": "test",
"script": {
"exec": [
""
],
"type": "text/javascript",
"packages": {}
}
},
{
"listen": "prerequest",
"script": {
"exec": [
""
],
"type": "text/javascript",
"packages": {}
}
}
],
"protocolProfileBehavior": {
"disableBodyPruning": true
},
"request": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"offerId\":\"{{OFFER_ID}}\",\n \"credentialConfigurationId\": \"w3c_vc_credential\",\n \"credential\": {\n \"credentialSubject\": {\n \"first_name\": \"Ferris\",\n \"last_name\": \"Crabman\",\n \"dob\": \"1982-01-01\"\n }\n }\n}",
daniel-mader marked this conversation as resolved.
Show resolved Hide resolved
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/v0/credentials",
"host": [
"{{HOST}}"
],
"path": [
"v0",
"credentials"
]
}
},
"response": []
},
{
"name": "offers",
"event": [
Expand Down Expand Up @@ -177,6 +229,58 @@
},
"response": []
},
{
"name": "all_offers",
"event": [
{
"listen": "test",
"script": {
"exec": [
""
],
"type": "text/javascript",
"packages": {}
}
},
{
"listen": "prerequest",
"script": {
"exec": [
""
],
"type": "text/javascript",
"packages": {}
}
}
],
"protocolProfileBehavior": {
"disableBodyPruning": true
},
"request": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"offerId\": \"{{OFFER_ID}}\"\n}",
daniel-mader marked this conversation as resolved.
Show resolved Hide resolved
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/v0/offers",
"host": [
"{{HOST}}"
],
"path": [
"v0",
"offers"
]
}
},
"response": []
},
{
"name": "offers_send",
"request": {
Expand Down
2 changes: 1 addition & 1 deletion agent_api_rest/src/holder/holder/credentials/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use serde_json::json;

#[axum_macros::debug_handler]
pub(crate) async fn credentials(State(state): State<HolderState>) -> Response {
match query_handler("all_credentials", &state.query.all_credentials).await {
match query_handler("all_holder_credentials", &state.query.all_holder_credentials).await {
Ok(Some(all_credentials_view)) => (StatusCode::OK, Json(all_credentials_view)).into_response(),
Ok(None) => (StatusCode::OK, Json(json!({}))).into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
Expand Down
10 changes: 5 additions & 5 deletions agent_api_rest/src/holder/holder/offers/accept.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use agent_holder::{
credential::command::CredentialCommand,
offer::{command::OfferCommand, queries::OfferView},
offer::{command::OfferCommand, queries::ReceivedOfferView},
state::HolderState,
};
use agent_shared::handlers::{command_handler, query_handler};
Expand All @@ -18,8 +18,8 @@ pub(crate) async fn accept(State(state): State<HolderState>, Path(offer_id): Pat
// Furthermore, the Application Layer (not implemented yet) should be kept very thin as well. See: https://github.com/impierce/ssi-agent/issues/114

// Accept the Credential Offer if it exists
match query_handler(&offer_id, &state.query.offer).await {
Ok(Some(OfferView { .. })) => {
match query_handler(&offer_id, &state.query.received_offer).await {
Ok(Some(ReceivedOfferView { .. })) => {
let command = OfferCommand::AcceptCredentialOffer {
offer_id: offer_id.clone(),
};
Expand All @@ -45,8 +45,8 @@ pub(crate) async fn accept(State(state): State<HolderState>, Path(offer_id): Pat
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
}

let credentials = match query_handler(&offer_id, &state.query.offer).await {
Ok(Some(OfferView { credentials, .. })) => credentials,
let credentials = match query_handler(&offer_id, &state.query.received_offer).await {
Ok(Some(ReceivedOfferView { credentials, .. })) => credentials,
_ => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
};

Expand Down
2 changes: 1 addition & 1 deletion agent_api_rest/src/holder/holder/offers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use serde_json::json;

#[axum_macros::debug_handler]
pub(crate) async fn offers(State(state): State<HolderState>) -> Response {
match query_handler("all_offers", &state.query.all_offers).await {
match query_handler("all_received_offers", &state.query.all_received_offers).await {
Ok(Some(all_offers_view)) => (StatusCode::OK, Json(all_offers_view)).into_response(),
Ok(None) => (StatusCode::OK, Json(json!({}))).into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
Expand Down
11 changes: 11 additions & 0 deletions agent_api_rest/src/issuance/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;
use tracing::info;

use serde_json::json;

#[axum_macros::debug_handler]
pub(crate) async fn get_credentials(State(state): State<IssuanceState>, Path(credential_id): Path<String>) -> Response {
// Get the credential if it exists.
Expand Down Expand Up @@ -160,6 +162,15 @@ pub(crate) async fn credentials(
}
}

#[axum_macros::debug_handler]
pub(crate) async fn all_credentials(State(state): State<IssuanceState>) -> Response {
match query_handler("all_credentials", &state.query.all_credentials).await {
Ok(Some(all_credentials_view)) => (StatusCode::OK, Json(all_credentials_view)).into_response(),
Ok(None) => (StatusCode::OK, Json(json!({}))).into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
}

#[cfg(test)]
pub mod tests {
use super::*;
Expand Down
6 changes: 4 additions & 2 deletions agent_api_rest/src/issuance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub mod offers;
use agent_issuance::state::IssuanceState;
use axum::routing::get;
use axum::{routing::post, Router};
use credentials::all_credentials;
use offers::all_offers;

use crate::issuance::{
credential_issuer::{
Expand All @@ -21,9 +23,9 @@ pub fn router(issuance_state: IssuanceState) -> Router {
.nest(
API_VERSION,
Router::new()
.route("/credentials", post(credentials))
.route("/credentials", post(credentials).get(all_credentials))
.route("/credentials/:credential_id", get(get_credentials))
.route("/offers", post(offers))
.route("/offers", post(offers).get(all_offers))
.route("/offers/send", post(send)),
)
.route(
Expand Down
10 changes: 10 additions & 0 deletions agent_api_rest/src/issuance/offers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use axum::{
};
use hyper::header;
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_json::Value;
use tracing::info;

Expand Down Expand Up @@ -81,6 +82,15 @@ pub(crate) async fn offers(State(state): State<IssuanceState>, Json(payload): Js
}
}

#[axum_macros::debug_handler]
pub(crate) async fn all_offers(State(state): State<IssuanceState>) -> Response {
match query_handler("all_offers", &state.query.all_offers).await {
Ok(Some(all_offers_view)) => (StatusCode::OK, Json(all_offers_view)).into_response(),
Ok(None) => (StatusCode::OK, Json(json!({}))).into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
}

#[cfg(test)]
pub mod tests {
use super::*;
Expand Down
20 changes: 18 additions & 2 deletions agent_application/docker/db/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ CREATE TABLE offer
PRIMARY KEY (view_id)
);

CREATE TABLE all_offers
(
view_id text NOT NULL,
version bigint CHECK (version >= 0) NOT NULL,
payload json NOT NULL,
PRIMARY KEY (view_id)
);

CREATE TABLE pre_authorized_code
(
view_id text NOT NULL,
Expand All @@ -42,6 +50,14 @@ CREATE TABLE credential
PRIMARY KEY (view_id)
);

CREATE TABLE all_credentials
(
view_id text NOT NULL,
version bigint CHECK (version >= 0) NOT NULL,
payload json NOT NULL,
PRIMARY KEY (view_id)
);

CREATE TABLE server_config
(
view_id text NOT NULL,
Expand All @@ -58,7 +74,7 @@ CREATE TABLE received_offer
PRIMARY KEY (view_id)
);

CREATE TABLE all_offers
CREATE TABLE all_received_offers
(
view_id text NOT NULL,
version bigint CHECK (version >= 0) NOT NULL,
Expand All @@ -75,7 +91,7 @@ CREATE TABLE holder_credential
);


CREATE TABLE all_credentials
CREATE TABLE all_holder_credentials
(
view_id text NOT NULL,
version bigint CHECK (version >= 0) NOT NULL,
Expand Down
8 changes: 4 additions & 4 deletions agent_holder/src/credential/queries/all_credentials.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use super::CredentialView;
use super::HolderCredentialView;
use crate::credential::queries::Credential;
use cqrs_es::{EventEnvelope, View};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct AllCredentialsView {
pub struct AllHolderCredentialsView {
#[serde(flatten)]
pub credentials: HashMap<String, CredentialView>,
pub credentials: HashMap<String, HolderCredentialView>,
}

impl View<Credential> for AllCredentialsView {
impl View<Credential> for AllHolderCredentialsView {
fn update(&mut self, event: &EventEnvelope<Credential>) {
self.credentials
// Get the entry for the aggregate_id
Expand Down
4 changes: 2 additions & 2 deletions agent_holder/src/credential/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use cqrs_es::{EventEnvelope, View};
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct CredentialView {
pub struct HolderCredentialView {
pub credential_id: Option<String>,
pub offer_id: Option<String>,
pub credential: Option<serde_json::Value>,
}

impl View<Credential> for CredentialView {
impl View<Credential> for HolderCredentialView {
fn update(&mut self, event: &EventEnvelope<Credential>) {
use CredentialEvent::*;

Expand Down
8 changes: 4 additions & 4 deletions agent_holder/src/offer/queries/all_offers.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use super::OfferView;
use super::ReceivedOfferView;
use crate::offer::queries::Offer;
use cqrs_es::{EventEnvelope, View};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct AllOffersView {
pub struct AllReceivedOffersView {
#[serde(flatten)]
pub offers: HashMap<String, OfferView>,
pub offers: HashMap<String, ReceivedOfferView>,
}

impl View<Offer> for AllOffersView {
impl View<Offer> for AllReceivedOffersView {
fn update(&mut self, event: &EventEnvelope<Offer>) {
self.offers
// Get the entry for the aggregate_id
Expand Down
4 changes: 2 additions & 2 deletions agent_holder/src/offer/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct OfferView {
pub struct ReceivedOfferView {
pub credential_offer: Option<CredentialOfferParameters>,
pub status: Status,
pub credential_configurations: Option<HashMap<String, CredentialConfigurationsSupportedObject>>,
pub token_response: Option<TokenResponse>,
pub credentials: Vec<serde_json::Value>,
}

impl View<Offer> for OfferView {
impl View<Offer> for ReceivedOfferView {
fn update(&mut self, event: &EventEnvelope<Offer>) {
use crate::offer::event::OfferEvent::*;

Expand Down
Loading