Add delphi integration, fix search showing plugins

This commit is contained in:
Jai A 2025-01-08 22:06:05 -08:00
parent adf3d9540d
commit 8e754cfeb5
No known key found for this signature in database
GPG Key ID: 9A9F9B7250E9883C
7 changed files with 99 additions and 30 deletions

View File

@ -112,4 +112,7 @@ ADITUDE_API_KEY=none
PYRO_API_KEY=none
BREX_API_URL=https://platform.brexapis.com/v2/
BREX_API_KEY=none
BREX_API_KEY=none
DELPHI_URL=none
DELPHI_SLACK_WEBHOOK=none

View File

@ -489,7 +489,10 @@ pub fn check_env_vars() -> bool {
failed |= check_var::<String>("PYRO_API_KEY");
failed |= check_var::<String>("BREX_API_URL");
failed |= check_var::<String>("BREX_API_KEY");
failed |= check_var::<String>("DELPHI_URL");
failed
}

View File

@ -18,7 +18,7 @@ use std::io::{Cursor, Read};
use std::time::Duration;
use zip::ZipArchive;
const AUTOMOD_ID: i64 = 0;
pub const AUTOMOD_ID: i64 = 0;
pub struct ModerationMessages {
pub messages: Vec<ModerationMessage>,

View File

@ -1,10 +1,13 @@
use crate::auth::validate::get_user_record_from_bearer_token;
use crate::database::models::thread_item::ThreadMessageBuilder;
use crate::database::redis::RedisPool;
use crate::models::analytics::Download;
use crate::models::ids::ProjectId;
use crate::models::pats::Scopes;
use crate::models::threads::MessageBody;
use crate::queue::analytics::AnalyticsQueue;
use crate::queue::maxmind::MaxMindIndexer;
use crate::queue::moderation::AUTOMOD_ID;
use crate::queue::payouts::PayoutsQueue;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
@ -23,7 +26,8 @@ pub fn config(cfg: &mut web::ServiceConfig) {
web::scope("admin")
.service(count_download)
.service(force_reindex)
.service(get_balances),
.service(get_balances)
.service(delphi_result_ingest),
);
}
@ -178,3 +182,70 @@ pub async fn get_balances(
"tremendous": tremendous,
})))
}
#[derive(Deserialize)]
pub struct DelphiIngest {
pub url: String,
pub project_id: crate::models::ids::ProjectId,
pub version_id: crate::models::ids::VersionId,
pub issues: Vec<String>,
}
#[post("/_delphi", guard = "admin_key_guard")]
pub async fn delphi_result_ingest(
pool: web::Data<PgPool>,
redis: web::Data<RedisPool>,
body: web::Json<DelphiIngest>,
) -> Result<HttpResponse, ApiError> {
let webhook_url = dotenvy::var("DELPHI_SLACK_WEBHOOK")?;
let project = crate::database::models::Project::get_id(
body.project_id.into(),
&**pool,
&redis,
)
.await?
.ok_or_else(|| {
ApiError::InvalidInput(format!(
"Project {} does not exist",
body.project_id
))
})?;
crate::util::webhook::send_slack_webhook(
body.project_id,
&pool,
&redis,
webhook_url,
Some(format!(
"Suspicious traces found at {}. Traces: {}",
body.url,
body.issues.join(", ")
)),
)
.await
.ok();
let mut transaction = pool.begin().await?;
ThreadMessageBuilder {
author_id: Some(crate::database::models::UserId(AUTOMOD_ID)),
body: MessageBody::Text {
body: format!(
"WSR; Suspicious traces found for version_id {}. Traces: {}",
body.version_id,
body.issues.join(", ")
),
private: true,
replying_to: None,
associated_images: vec![],
},
thread_id: project.thread_id,
hide_identity: false,
}
.insert(&mut transaction)
.await?;
transaction.commit().await?;
Ok(HttpResponse::NoContent().finish())
}

View File

@ -61,11 +61,6 @@ pub async fn project_search(
let facets: Option<Vec<Vec<String>>> = if let Some(facets) = info.facets {
let facets = serde_json::from_str::<Vec<Vec<String>>>(&facets)?;
// These loaders specifically used to be combined with 'mod' to be a plugin, but now
// they are their own loader type. We will convert 'mod' to 'mod' OR 'plugin'
// as it essentially was before.
let facets = v2_reroute::convert_plugin_loader_facets_v3(facets);
Some(
facets
.into_iter()

View File

@ -190,28 +190,6 @@ pub fn convert_side_types_v3(
fields
}
// Converts plugin loaders from v2 to v3, for search facets
// Within every 1st and 2nd level (the ones allowed in v2), we convert every instance of:
// "project_type:mod" to "project_type:plugin" OR "project_type:mod"
pub fn convert_plugin_loader_facets_v3(
facets: Vec<Vec<String>>,
) -> Vec<Vec<String>> {
facets
.into_iter()
.map(|inner_facets| {
if inner_facets == ["project_type:mod"] {
vec![
"project_type:plugin".to_string(),
"project_type:datapack".to_string(),
"project_type:mod".to_string(),
]
} else {
inner_facets
}
})
.collect::<Vec<_>>()
}
// Convert search facets from V3 back to v2
// this is not lossless. (See tests)
pub fn convert_side_types_v2(

View File

@ -31,6 +31,7 @@ use actix_web::{web, HttpRequest, HttpResponse};
use chrono::Utc;
use futures::stream::StreamExt;
use itertools::Itertools;
use log::error;
use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPool;
use std::collections::{HashMap, HashSet};
@ -980,6 +981,24 @@ pub async fn upload_file(
}
}
let url = format!("{cdn_url}/{file_path_encode}");
let client = reqwest::Client::new();
let delphi_url = dotenvy::var("DELPHI_URL")?;
let res = client
.post(delphi_url)
.json(&serde_json::json!({
"url": url,
"project_id": project_id,
"version_id": version_id,
}))
.send()
.await?;
if !res.status().is_success() {
error!("Failed to upload file to Delphi: {url}");
}
version_files.push(VersionFileBuilder {
filename: file_name.to_string(),
url: format!("{cdn_url}/{file_path_encode}"),