use crate::codecs::decode::enums::enum_proto_name;
use crate::codecs::scalars::format_uint64_id;
use crate::models::{ApiKeySummary, ApiKeysList, ResolvedAccount, ResolvedAccountsList};
use crate::proto::auth::v1::{
ApiKey as ProtoApiKey, CreateApiKeyResponse, GetApiKeyResponse, ListApiKeysResponse,
ResolveAccountResponse, ResolvedAccount as ProtoResolvedAccount, UpdateApiKeyResponse,
};
pub fn api_key_from_proto(msg: &ProtoApiKey) -> ApiKeySummary {
let status = enum_proto_name(&msg.status);
ApiKeySummary {
key_id: msg.key_id.clone(),
label: msg.label.clone(),
status,
public_key_ed25519: hex::encode(&msg.public_key_ed25519),
created_at: msg.created_at.as_option().cloned(),
last_used_at: msg.last_used_at.as_option().cloned(),
updated_at: msg.updated_at.as_option().cloned(),
revision: msg.revision,
}
}
pub fn api_keys_list_from_proto(msg: &ListApiKeysResponse) -> ApiKeysList {
ApiKeysList {
keys: msg.api_keys.iter().map(api_key_from_proto).collect(),
}
}
pub fn api_key_from_get_proto(msg: &GetApiKeyResponse) -> Option<ApiKeySummary> {
msg.api_key.as_option().map(api_key_from_proto)
}
pub fn api_key_from_create_proto(msg: &CreateApiKeyResponse) -> Option<ApiKeySummary> {
msg.api_key.as_option().map(api_key_from_proto)
}
pub fn api_key_from_update_proto(msg: &UpdateApiKeyResponse) -> Option<ApiKeySummary> {
msg.api_key.as_option().map(api_key_from_proto)
}
pub fn resolved_account_from_proto(msg: &ProtoResolvedAccount) -> ResolvedAccount {
let username = if !msg.subaccount_label.is_empty() {
msg.subaccount_label.clone()
} else {
msg.root_username.clone()
};
ResolvedAccount {
account_id: format_uint64_id(msg.account_id),
username,
smart_account_address: msg.smart_account_address.clone(),
}
}
pub fn resolved_accounts_from_proto(msg: &ResolveAccountResponse) -> ResolvedAccountsList {
ResolvedAccountsList {
accounts: msg
.matches
.iter()
.map(resolved_account_from_proto)
.collect(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::proto::auth::v1::ApiKeyStatus;
use buffa_types::google::protobuf::Timestamp;
#[test]
fn api_keys_list_maps_status() {
let msg = ListApiKeysResponse {
api_keys: vec![ProtoApiKey {
key_id: "key-1".into(),
label: "bot".into(),
status: ApiKeyStatus::Active.into(),
created_at: Timestamp {
seconds: 1,
..Default::default()
}
.into(),
last_used_at: Timestamp {
seconds: 2,
..Default::default()
}
.into(),
updated_at: Timestamp {
seconds: 3,
nanos: 123_456_000,
..Default::default()
}
.into(),
revision: 9,
..Default::default()
}],
..Default::default()
};
let result = api_keys_list_from_proto(&msg);
assert_eq!(result.keys.len(), 1);
assert_eq!(result.keys[0].key_id, "key-1");
assert_eq!(result.keys[0].status, "ACTIVE");
assert_eq!(result.keys[0].created_at.as_ref().unwrap().seconds, 1);
assert_eq!(result.keys[0].last_used_at.as_ref().unwrap().seconds, 2);
assert_eq!(
result.keys[0].updated_at.as_ref().unwrap().nanos,
123_456_000
);
assert_eq!(result.keys[0].revision, 9);
}
#[test]
fn resolved_accounts_formats_id() {
let msg = ResolveAccountResponse {
matches: vec![ProtoResolvedAccount {
smart_account_address: "0x123".into(),
kind: "subaccount".into(),
account_id: 99,
..Default::default()
}],
..Default::default()
};
let result = resolved_accounts_from_proto(&msg);
assert_eq!(result.accounts.len(), 1);
assert_eq!(result.accounts[0].account_id, format_uint64_id(99));
assert_eq!(result.accounts[0].smart_account_address, "0x123");
}
}