Skip to main content
Glama
attributes.rs6.58 kB
use axum::{ BoxError, Json, Router, error_handling::HandleErrorLayer, extract::Path, http::StatusCode, response::{ IntoResponse, Response, }, routing::{ delete, post, put, }, }; use dal::{ AttributeValue, ChangeSet, ChangeSetId, ComponentId, WorkspacePk, attribute::attributes::{ AttributeSources, AttributeValueIdent, }, }; use sdf_core::{ api_error::ApiError, force_change_set_response::ForceChangeSetResponse, }; use sdf_extract::{ PosthogEventTracker, change_set::ChangeSetDalContext, }; use serde_json::json; use si_events::audit_log::AuditLogKind; use tower::ServiceBuilder; use tower_http::decompression::RequestDecompressionLayer; use super::{ ComponentIdFromPath, Error, Result, }; use crate::app_state::AppState; pub fn v2_routes() -> Router<AppState> { Router::new() .route( "/", put(update_attributes).layer( ServiceBuilder::new() .layer(HandleErrorLayer::new(handle_decompression_error)) .layer( RequestDecompressionLayer::new() .gzip(true) .deflate(true) .pass_through_unaccepted(true), ), ), ) .route("/default_source", put(set_as_default_source)) .route("/default_source", delete(delete_default_source)) .route("/enqueue", post(enqueue_prototype_function)) } async fn handle_decompression_error(err: BoxError) -> Response { ApiError::new(StatusCode::UNSUPPORTED_MEDIA_TYPE, err.to_string()).into_response() } async fn set_as_default_source( ChangeSetDalContext(ref mut ctx): ChangeSetDalContext, tracker: PosthogEventTracker, Path(ComponentIdFromPath { component_id }): Path<ComponentIdFromPath>, Json(av_ident): Json<AttributeValueIdent>, ) -> Result<ForceChangeSetResponse<()>> { let force_change_set_id = ChangeSet::force_new(ctx).await?; let av_ident_string: String = av_ident.clone().into(); let attribute_value_id = av_ident .resolve(ctx, component_id) .await? .ok_or(Error::AttributeValueNotFound( av_ident_string.clone(), component_id, ))?; AttributeValue::set_as_default_subscription_source(ctx, attribute_value_id).await?; ctx.write_audit_log( AuditLogKind::SetDefaultSubscriptionSource { component_id, av_id: attribute_value_id, av_identifier: av_ident_string.clone(), }, av_ident_string.clone(), ) .await?; ctx.commit().await?; tracker.track( ctx, "set_default_source", json!({ "how": "/component/attributes/default_source", "component_id": component_id, "change_set_id": ctx.change_set_id(), "av_id": attribute_value_id, "av_identifier": av_ident_string, }), ); Ok(ForceChangeSetResponse::empty(force_change_set_id)) } async fn delete_default_source( ChangeSetDalContext(ref mut ctx): ChangeSetDalContext, tracker: PosthogEventTracker, Path(ComponentIdFromPath { component_id }): Path<ComponentIdFromPath>, Json(av_ident): Json<AttributeValueIdent>, ) -> Result<ForceChangeSetResponse<()>> { let force_change_set_id = ChangeSet::force_new(ctx).await?; let av_ident_string: String = av_ident.clone().into(); let attribute_value_id = av_ident .resolve(ctx, component_id) .await? .ok_or(Error::AttributeValueNotFound( av_ident_string.clone(), component_id, ))?; AttributeValue::remove_default_subscription_source(ctx, attribute_value_id).await?; ctx.write_audit_log( AuditLogKind::RemoveDefaultSubscriptionSource { component_id, av_id: attribute_value_id, av_identifier: av_ident_string.clone(), }, av_ident_string.clone(), ) .await?; ctx.commit().await?; tracker.track( ctx, "delete_default_source", json!({ "how": "/component/attributes/default_source", "component_id": component_id, "change_set_id": ctx.change_set_id(), "av_id": attribute_value_id, "av_identifier": av_ident_string, }), ); Ok(ForceChangeSetResponse::empty(force_change_set_id)) } async fn update_attributes( ChangeSetDalContext(ref mut ctx): ChangeSetDalContext, tracker: PosthogEventTracker, Path(ComponentIdFromPath { component_id }): Path<ComponentIdFromPath>, Json(updates): Json<AttributeSources>, ) -> Result<ForceChangeSetResponse<()>> { let force_change_set_id = ChangeSet::force_new(ctx).await?; let counts = dal::update_attributes(ctx, component_id, updates).await?; ctx.commit().await?; tracker.track( ctx, "component_attributes_updated", json!({ "how": "/component/attributes", "component_id": component_id, "change_set_id": ctx.change_set_id(), "set_count": counts.set_count, "unset_count": counts.unset_count, "subscription_count": counts.subscription_count, }), ); Ok(ForceChangeSetResponse::empty(force_change_set_id)) } async fn enqueue_prototype_function( ChangeSetDalContext(ref mut ctx): ChangeSetDalContext, tracker: PosthogEventTracker, Path((_workspace_pk, _change_set_id, component_id)): Path<( WorkspacePk, ChangeSetId, ComponentId, )>, Json(values): Json<Vec<AttributeValueIdent>>, ) -> Result<()> { let mut did_enqueue = false; for value in values { if let Some(attribute_value_id) = value.resolve(ctx, component_id).await? { if AttributeValue::is_set_by_dependent_function(ctx, attribute_value_id).await? { ctx.add_dependent_values_and_enqueue(vec![attribute_value_id]) .await?; did_enqueue = true; } } } if did_enqueue { ctx.commit().await?; } tracker.track( ctx, "enqueue_attribute_prototype", json!({ "how": "/component/attributes", "component_id": component_id, "change_set_id": ctx.change_set_id(), }), ); Ok(()) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server