use crate::client::Client;
use crate::errors::Error;
use crate::insert_optional;
use crate::KeygenResponseData;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum TokenKind {
#[serde(rename = "activation-token")]
ActivationToken,
#[serde(rename = "product-token")]
ProductToken,
#[serde(rename = "user-token")]
UserToken,
#[serde(rename = "support-token")]
SupportToken,
#[serde(rename = "sales-token")]
SalesToken,
#[serde(rename = "developer-token")]
DeveloperToken,
#[serde(rename = "admin-token")]
AdminToken,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenAttributes {
pub kind: TokenKind,
pub token: Option<String>, pub name: Option<String>,
pub expiry: Option<String>,
pub permissions: Option<Vec<String>>,
pub metadata: Option<HashMap<String, serde_json::Value>>,
pub created: String,
pub updated: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct TokenResponse {
pub data: KeygenResponseData<TokenAttributes>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct TokensResponse {
pub data: Vec<KeygenResponseData<TokenAttributes>>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ListTokensOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(rename = "page[size]", skip_serializing_if = "Option::is_none")]
pub page_size: Option<u32>,
#[serde(rename = "page[number]", skip_serializing_if = "Option::is_none")]
pub page_number: Option<u32>,
#[serde(rename = "bearer[type]", skip_serializing_if = "Option::is_none")]
pub bearer_type: Option<String>,
#[serde(rename = "bearer[id]", skip_serializing_if = "Option::is_none")]
pub bearer_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegenerateTokenRequest {
pub name: Option<String>,
pub expiry: Option<String>,
pub permissions: Option<Vec<String>>,
pub metadata: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CreateTokenRequest {
pub name: Option<String>,
pub expiry: Option<String>,
pub permissions: Option<Vec<String>>,
pub metadata: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone)]
pub struct Token {
pub id: String,
pub kind: TokenKind,
pub token: Option<String>,
pub name: Option<String>,
pub expiry: Option<String>,
pub permissions: Option<Vec<String>>,
pub metadata: Option<HashMap<String, serde_json::Value>>,
pub created: String,
pub updated: String,
}
impl Token {
pub(crate) fn from(data: KeygenResponseData<TokenAttributes>) -> Token {
Token {
id: data.id,
kind: data.attributes.kind,
token: data.attributes.token,
name: data.attributes.name,
expiry: data.attributes.expiry,
permissions: data.attributes.permissions,
metadata: data.attributes.metadata,
created: data.attributes.created,
updated: data.attributes.updated,
}
}
pub async fn list(options: Option<ListTokensOptions>) -> Result<Vec<Token>, Error> {
let client = Client::from_global_config()?;
let response = client.get("tokens", options.as_ref()).await?;
let tokens_response: TokensResponse = serde_json::from_value(response.body)?;
Ok(tokens_response.data.into_iter().map(Token::from).collect())
}
pub async fn get(id: &str) -> Result<Token, Error> {
let client = Client::from_global_config()?;
let endpoint = format!("tokens/{id}");
let response = client.get(&endpoint, None::<&()>).await?;
let token_response: TokenResponse = serde_json::from_value(response.body)?;
Ok(Token::from(token_response.data))
}
pub async fn regenerate(&self, request: RegenerateTokenRequest) -> Result<Token, Error> {
let client = Client::from_global_config()?;
let endpoint = format!("tokens/{}", self.id);
let mut attributes = serde_json::Map::new();
insert_optional(&mut attributes, "name", request.name)?;
insert_optional(&mut attributes, "expiry", request.expiry)?;
insert_optional(&mut attributes, "permissions", request.permissions)?;
insert_optional(&mut attributes, "metadata", request.metadata)?;
let body = serde_json::json!({
"data": {
"type": "tokens",
"attributes": attributes
}
});
let response = client.put(&endpoint, Some(&body), None::<&()>).await?;
let token_response: TokenResponse = serde_json::from_value(response.body)?;
Ok(Token::from(token_response.data))
}
pub async fn revoke(&self) -> Result<(), Error> {
let client = Client::from_global_config()?;
let endpoint = format!("tokens/{}", self.id);
client.delete::<(), ()>(&endpoint, None::<&()>).await?;
Ok(())
}
pub fn is_expired(&self) -> bool {
if let Some(expiry) = &self.expiry {
if let Ok(expiry_time) = chrono::DateTime::parse_from_rfc3339(expiry) {
return chrono::Utc::now() > expiry_time;
}
}
false
}
pub fn has_permission(&self, permission: &str) -> bool {
if let Some(permissions) = &self.permissions {
permissions.contains(&permission.to_string())
} else {
false
}
}
pub fn get_token(&self) -> Option<&str> {
self.token.as_deref()
}
}
pub(crate) fn token_request_attributes(
request: Option<&CreateTokenRequest>,
) -> Result<serde_json::Map<String, serde_json::Value>, Error> {
let mut attributes = serde_json::Map::new();
if let Some(request) = request {
insert_optional(&mut attributes, "name", request.name.clone())?;
insert_optional(&mut attributes, "expiry", request.expiry.clone())?;
insert_optional(&mut attributes, "permissions", request.permissions.clone())?;
insert_optional(&mut attributes, "metadata", request.metadata.clone())?;
}
Ok(attributes)
}