Skip to content

Commit

Permalink
feat: webhook crud
Browse files Browse the repository at this point in the history
  • Loading branch information
mahatoankitkumar committed Dec 17, 2024
1 parent 0eb9086 commit feb1555
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-- This file should undo anything in `up.sql`
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- Your SQL goes here
-- Name: webhooks; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.webhooks (
name text PRIMARY KEY,
description text NOT NULL,
enabled boolean NOT NULL DEFAULT true,
url text NOT NULL,
method text NOT NULL DEFAULT 'POST',
version text NOT NULL,
custom_headers json,
events varchar(100)[] CHECK (array_position(events, NULL) IS NULL),
max_retries integer NOT NULL DEFAULT 0,
last_triggered_at timestamp,
created_by text NOT NULL,
created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
);
--
-- Name: webhooks webhooks_audit; Type: TRIGGER; Schema: public; Owner: -
--
CREATE TRIGGER webhooks_audit AFTER INSERT OR DELETE OR UPDATE ON public.webhooks FOR EACH ROW EXECUTE FUNCTION public.event_logger();
1 change: 1 addition & 0 deletions crates/context_aware_config/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pub mod default_config;
pub mod dimension;
pub mod functions;
pub mod type_templates;
pub mod webhooks;
3 changes: 3 additions & 0 deletions crates/context_aware_config/src/api/webhooks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod handlers;
pub mod types;
pub use handlers::endpoints;
73 changes: 73 additions & 0 deletions crates/context_aware_config/src/api/webhooks/handlers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use actix_web::{
post,
web::{self, Data, Json},
HttpResponse, Scope,
};
use chrono::Utc;
use service_utils::service::types::{AppState, DbConnection};
use superposition_macros::{bad_argument, unexpected_error};
use superposition_types::{result as superposition, webhook, User};

use super::types::CreateWebhookRequest;
use diesel::{delete, ExpressionMethods, QueryDsl, RunQueryDsl};
use superposition_types::cac::models::{self as models, Webhooks};
use superposition_types::cac::schema::webhooks::dsl::webhooks;

pub fn endpoints() -> Scope {
Scope::new("").service(create)
}

#[post("")]
async fn create(
state: Data<AppState>,
request: web::Json<CreateWebhookRequest>,
db_conn: DbConnection,
user: User,
) -> superposition::Result<Json<Webhooks>> {
let DbConnection(mut conn) = db_conn;
let req = request.into_inner();

let now = Utc::now().naive_utc();
let webhook = Webhooks {
name: req.name,
description: req.description,
enabled: req.enabled,
url: req.url,
method: req.method,
version: req.version.unwrap_or("v1".to_owned()),
custom_headers: req.custom_headers,
events: req.events,
max_retries: 0,
last_triggered_at: None,
created_by: user.email,
created_at: now,
updated_at: now,
};

let insert: Result<Webhooks, diesel::result::Error> = diesel::insert_into(webhooks)
.values(&webhook)
.get_result(&mut conn);

match insert {
Ok(res) => Ok(Json(res)),
Err(e) => match e {
diesel::result::Error::DatabaseError(kind, e) => {
log::error!("Function error: {:?}", e);
match kind {
diesel::result::DatabaseErrorKind::UniqueViolation => {
Err(bad_argument!("Webhook already exists."))
}
_ => Err(unexpected_error!(
"Something went wrong, failed to create the webhook"
)),
}
}
_ => {
log::error!("Webhook creation failed with error: {e}");
Err(unexpected_error!(
"An error occured please contact the admin."
))
}
},
}
}
Empty file.
14 changes: 14 additions & 0 deletions crates/context_aware_config/src/api/webhooks/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use serde::Deserialize;
use serde_json::Value;

#[derive(Debug, Deserialize)]
pub struct CreateWebhookRequest {
pub name: String,
pub description: String,
pub enabled: bool,
pub url: String,
pub method: String,
pub version: Option<String>,
pub custom_headers: Option<Value>,
pub events: Option<Vec<Option<String>>>,
}
13 changes: 12 additions & 1 deletion crates/service_utils/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ where
String::from("Failed to retrieve authentication token for the webhook. Please verify the credentials in TenantConfig.")
)
})?;
println!("<<>> {}", auth_token_value);
header_array.push((auth.key.clone(), auth_token_value));
}

Expand All @@ -435,6 +436,16 @@ where
HttpMethod::Post => http_client.post(&webhook_config.url),
HttpMethod::Get => http_client.get(&webhook_config.url),
};
let a = WebhookResponse {
event_info: WebhookEventInfo {
webhook_event: event.clone(),
time: Utc::now().naive_utc().to_string(),
tenant_id: tenant.to_string(),
config_version: config_version_opt.clone(),
},
payload,
};
println!("<<>> {}", serde_json::to_string(&a).unwrap());

let response = request_builder
.headers(headers.into())
Expand All @@ -449,7 +460,7 @@ where
})
.send()
.await;

println!("<<>> response: {:?}", response);
match response {
Ok(res) => {
match res.status() {
Expand Down
6 changes: 2 additions & 4 deletions crates/superposition/Superposition.cac.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,5 @@ tenant = { schema = { "type" = "string", "enum" = ["test", "dev"] } }

[context."$tenant == 'dev'"]
mandatory_dimensions = []
experiments_webhook_config = { "enabled" = false, "configuration" = { "url" = "http://localhost:8080/config/test", "method" = "Get", "custom_headers" = { "x-tenant" = "dev" }, "service_headers" = [
"ConfigVersion",
"TenantId",
], "authorization" = { key = "Authorization", value = "TOKEN_FOR_WEBHOOK" } } }
experiments_webhook_config = { "enabled" = true, "configuration" = { "url" = "https://integ.studio.juspay.in/api/v2/v1/invalidate", "method" = "Post", "custom_headers" = {}, "service_headers" = [
], "authorization" = { key = "juspay_token", value = "GALACTUS_API_KEY" } } }
5 changes: 5 additions & 0 deletions crates/superposition/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ async fn main() -> Result<()> {
AppExecutionScopeMiddlewareFactory::new(AppScope::EXPERIMENTATION),
),
)
.service(
scope("/webhook")
.wrap(AppExecutionScopeMiddlewareFactory::new(AppScope::CAC))
.service(webhooks::endpoints()),
)
/***************************** UI Routes ******************************/
.route("/fxn/{tail:.*}", leptos_actix::handle_server_fns())
// serve JS/WASM/CSS from `pkg`
Expand Down
26 changes: 25 additions & 1 deletion crates/superposition_types/src/cac/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{Cac, Condition, Contextual, Overridden, Overrides};
#[cfg(feature = "diesel_derives")]
use super::schema::{
config_versions, contexts, default_configs, dimensions, event_log, functions,
type_templates,
type_templates, webhooks,
};

#[derive(Clone, Serialize, Debug)]
Expand Down Expand Up @@ -151,3 +151,27 @@ pub struct TypeTemplates {
pub last_modified_at: NaiveDateTime,
pub last_modified_by: String,
}

#[derive(Serialize, Clone, Debug)]
#[cfg_attr(
feature = "diesel_derives",
derive(Queryable, Selectable, Insertable, AsChangeset)
)]
#[cfg_attr(feature = "diesel_derives", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "diesel_derives", diesel(table_name = webhooks))]
#[cfg_attr(feature = "diesel_derives", diesel(primary_key(name)))]
pub struct Webhooks {
pub name: String,
pub description: String,
pub enabled: bool,
pub url: String,
pub method: String,
pub version: String,
pub custom_headers: Option<Value>,
pub events: Option<Vec<Option<String>>>,
pub max_retries: i32,
pub last_triggered_at: Option<NaiveDateTime>,
pub created_by: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
}
51 changes: 51 additions & 0 deletions crates/superposition_types/src/cac/schema.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
// @generated automatically by Diesel CLI.

pub mod sql_types {
#[derive(diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "experiment_status_type"))]
pub struct ExperimentStatusType;

#[derive(diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "not_null_text"))]
pub struct NotNullText;
}

diesel::table! {
config_versions (id) {
id -> Int8,
Expand Down Expand Up @@ -602,6 +612,27 @@ diesel::table! {
}
}

diesel::table! {
use diesel::sql_types::*;
use super::sql_types::NotNullText;
use super::sql_types::ExperimentStatusType;

experiments (id) {
id -> Int8,
created_at -> Timestamptz,
created_by -> Text,
last_modified -> Timestamptz,
name -> Text,
override_keys -> Array<Nullable<NotNullText>>,
status -> ExperimentStatusType,
traffic_percentage -> Int4,
context -> Json,
variants -> Json,
last_modified_by -> Text,
chosen_variant -> Nullable<Text>,
}
}

diesel::table! {
functions (function_name) {
function_name -> Text,
Expand Down Expand Up @@ -634,6 +665,24 @@ diesel::table! {
}
}

diesel::table! {
webhooks (name) {
name -> Text,
description -> Text,
enabled -> Bool,
url -> Text,
method -> Text,
version -> Text,
custom_headers -> Nullable<Json>,
events -> Nullable<Array<Nullable<Varchar>>>,
max_retries -> Int4,
last_triggered_at -> Nullable<Timestamp>,
created_by -> Text,
created_at -> Timestamp,
updated_at -> Timestamp,
}
}

diesel::joinable!(default_configs -> functions (function_name));
diesel::joinable!(dimensions -> functions (function_name));

Expand Down Expand Up @@ -684,6 +733,8 @@ diesel::allow_tables_to_appear_in_same_query!(
event_log_y2026m10,
event_log_y2026m11,
event_log_y2026m12,
experiments,
functions,
type_templates,
webhooks,
);
6 changes: 3 additions & 3 deletions crates/superposition_types/src/webhook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct Webhook {
pub authorization: Option<Authorization>,
}

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub enum WebhookEvent {
ExperimentCreated,
ExperimentStarted,
Expand All @@ -49,15 +49,15 @@ pub enum WebhookEvent {
ExperimentConcluded,
}

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct WebhookEventInfo {
pub webhook_event: WebhookEvent,
pub time: String,
pub tenant_id: String,
pub config_version: Option<String>,
}

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
pub struct WebhookResponse<T> {
pub event_info: WebhookEventInfo,
pub payload: T,
Expand Down
3 changes: 3 additions & 0 deletions setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!bin/sh
make setup && make tenant TENANT=mjos && make tenant TENANT=sdk_config
npm i

0 comments on commit feb1555

Please sign in to comment.