Skip to main content
Glama
approval_requirement.rs9.07 kB
//! This module provides functionality for creating, updating, deleting, getting and listing //! approval requirements when applying a change set. #![warn( bad_style, clippy::missing_panics_doc, clippy::panic, clippy::panic_in_result_fn, clippy::unwrap_in_result, clippy::unwrap_used, dead_code, improper_ctypes, missing_debug_implementations, // TODO(nick): restore this and clean up the mess. // missing_docs, no_mangle_generic_items, non_shorthand_field_patterns, overflowing_literals, path_statements, patterns_in_fns_without_body, unconditional_recursion, unreachable_pub, unused, unused_allocation, unused_comparisons, unused_parens, while_true )] use std::collections::{ HashMap, HashSet, }; use serde::{ Deserialize, Serialize, }; use si_events::{ merkle_tree_hash::MerkleTreeHash, workspace_snapshot::Change, }; use si_id::{ ApprovalRequirementDefinitionId, EntityId, UserPk, ulid::Ulid, }; use telemetry::prelude::*; use thiserror::Error; pub use crate::workspace_snapshot::traits::approval_requirement::{ ApprovalRequirementApprover, ApprovalRequirementRule, }; use crate::{ DalContext, WorkspaceSnapshotError, WsEvent, WsEventResult, WsPayload, layer_db_types::ApprovalRequirementDefinitionContentV1, workspace_snapshot::traits::approval_requirement::ApprovalRequirementExt, }; #[allow(missing_docs)] #[derive(Debug, Error)] pub enum ApprovalRequirementError { #[error("Entity not found: {0}")] EntityNotFound(EntityId), #[error("workspace snapshot error: {0}")] WorkspaceSnapshot(#[from] WorkspaceSnapshotError), } type Result<T> = std::result::Result<T, ApprovalRequirementError>; #[derive(Debug)] pub struct ApprovalRequirementExplicit { pub id: ApprovalRequirementDefinitionId, pub rule: ApprovalRequirementRule, } #[derive(Debug)] pub enum ApprovalRequirement { Explicit(ApprovalRequirementExplicit), Virtual(ApprovalRequirementRule), } impl ApprovalRequirement { #[instrument( name = "approval_requirement.new_definition", level = "debug", skip_all )] pub async fn new_definition( ctx: &DalContext, entity_id: impl Into<Ulid>, minimum_approvers_count: usize, approvers: HashSet<ApprovalRequirementApprover>, ) -> Result<ApprovalRequirementDefinitionId> { ctx.workspace_snapshot()? .new_definition(ctx, entity_id.into(), minimum_approvers_count, approvers) .await .map_err(Into::into) } #[instrument( name = "approval_requirement.remove_definition", level = "debug", skip_all )] pub async fn remove_definition( ctx: &DalContext, id: ApprovalRequirementDefinitionId, ) -> Result<()> { ctx.workspace_snapshot()? .remove_definition(id) .await .map_err(Into::into) } #[instrument( name = "approval_requirement.add_individual_approver_for_definition", level = "debug", skip_all )] pub async fn add_individual_approver_for_definition( ctx: &DalContext, id: ApprovalRequirementDefinitionId, user_id: UserPk, ) -> Result<()> { ctx.workspace_snapshot()? .add_individual_approver_for_definition(ctx, id, user_id) .await .map_err(Into::into) } #[instrument( name = "approval_requirement.remove_individual_approver_for_definition", level = "debug", skip_all )] pub async fn remove_individual_approver_for_definition( ctx: &DalContext, id: ApprovalRequirementDefinitionId, user_id: UserPk, ) -> Result<()> { ctx.workspace_snapshot()? .remove_individual_approver_for_definition(ctx, id, user_id) .await .map_err(Into::into) } #[instrument(name = "approval_requirement.list", level = "debug", skip_all)] pub async fn list( ctx: &DalContext, changes: &[Change], ) -> Result<(Vec<Self>, HashMap<EntityId, MerkleTreeHash>)> { ctx.workspace_snapshot()? .approval_requirements_for_changes(ctx, changes) .await .map_err(Into::into) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct ApprovalRequirementDefinition { pub id: ApprovalRequirementDefinitionId, pub required_count: usize, pub approvers: HashSet<ApprovalRequirementApprover>, } impl ApprovalRequirementDefinition { #[instrument( name = "approval_requirement_definition.list_for_entity_id", level = "debug", skip_all, fields(entity_id) )] pub async fn list_for_entity_id( ctx: &DalContext, entity_id: impl Into<Ulid>, ) -> Result<Vec<Self>> { let entity_id: EntityId = entity_id.into().into(); if let Some(approval_requirement_definitions) = ctx .workspace_snapshot()? .approval_requirement_definitions_for_entity_id_opt(ctx, entity_id) .await? { return Ok(approval_requirement_definitions); } Err(ApprovalRequirementError::EntityNotFound(entity_id)) } /// Used by the incomplete implementation of approval requirements in the split snapshot. /// Delete when approval requirements implemented pub fn fake() -> Self { Self { id: ApprovalRequirementDefinitionId::new(), required_count: 0, approvers: HashSet::new(), } } pub fn assemble( id: ApprovalRequirementDefinitionId, content: ApprovalRequirementDefinitionContentV1, ) -> Self { Self { id, required_count: content.minimum, approvers: content.approvers, } } pub async fn get_by_id(ctx: &DalContext, id: ApprovalRequirementDefinitionId) -> Result<Self> { ctx.workspace_snapshot()? .get_approval_requirement_definition_by_id(ctx, id) .await .map_err(Into::into) } pub async fn entity_id_for_approval_requirement_definition_id( ctx: &DalContext, id: ApprovalRequirementDefinitionId, ) -> Result<EntityId> { ctx.workspace_snapshot()? .entity_id_for_approval_requirement_definition_id(id) .await .map_err(Into::into) } } #[derive(Debug, Deserialize, Eq, PartialEq, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct ApprovalRequirementDefinitionCreatedPayload { entity_id: EntityId, approvers: Option<Vec<UserPk>>, } #[derive(Debug, Deserialize, Eq, PartialEq, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct ApprovalRequirementDefinitionRemovedPayload { approval_requirement_definition_id: ApprovalRequirementDefinitionId, } #[derive(Debug, Deserialize, Eq, PartialEq, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct IndividualApproverPayload { approval_requirement_definition_id: ApprovalRequirementDefinitionId, user_id: UserPk, } impl WsEvent { pub async fn requirement_created( ctx: &DalContext, entity_id: EntityId, approvers: Option<Vec<UserPk>>, ) -> WsEventResult<Self> { WsEvent::new( ctx, WsPayload::ApprovalRequirementDefinitionCreated( ApprovalRequirementDefinitionCreatedPayload { entity_id, approvers, }, ), ) .await } pub async fn requirement_removed( ctx: &DalContext, approval_requirement_definition_id: ApprovalRequirementDefinitionId, ) -> WsEventResult<Self> { WsEvent::new( ctx, WsPayload::ApprovalRequirementDefinitionRemoved( ApprovalRequirementDefinitionRemovedPayload { approval_requirement_definition_id, }, ), ) .await } pub async fn add_individual_approver_to_requirement( ctx: &DalContext, approval_requirement_definition_id: ApprovalRequirementDefinitionId, user_id: UserPk, ) -> WsEventResult<Self> { WsEvent::new( ctx, WsPayload::ApprovalRequirementAddIndividualApprover(IndividualApproverPayload { approval_requirement_definition_id, user_id, }), ) .await } pub async fn remove_individual_approver_from_requirement( ctx: &DalContext, approval_requirement_definition_id: ApprovalRequirementDefinitionId, user_id: UserPk, ) -> WsEventResult<Self> { WsEvent::new( ctx, WsPayload::ApprovalRequirementRemoveIndividualApprover(IndividualApproverPayload { approval_requirement_definition_id, user_id, }), ) .await } }

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