Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ deadpool-redis = "0.22.0"
strsim = "0.11.1"
hmac = "0.12.1"
rand = "0.10.0"
urlencoding = "2.1.3"
6 changes: 6 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ pub struct BackendServiceConfig {
pub api_key: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GeoCodingConfig {
pub base_url: String,
pub api_key: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct NotificationServiceConfig {
pub base_url: String,
pub ns_secret: String,
Expand All @@ -150,6 +155,7 @@ pub struct NotificationServiceConfig {
pub struct ServicesConfig {
pub seeker: BackendServiceConfig,
pub notification: NotificationServiceConfig,
pub geo_coding: GeoCodingConfig,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
Expand Down
52 changes: 51 additions & 1 deletion src/db/job.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
use chrono::{DateTime, Utc};
use serde_json::Value;
use sqlx::{query, Error, PgPool};
use sqlx::{query, query_as, Error, FromRow, PgPool};
use uuid::Uuid;
#[derive(Debug, FromRow)]
pub struct JobRow {
pub id: Uuid,
pub hash: String,
pub metadata: Option<Value>,
pub beckn_structure: Option<Value>,
}

#[derive(sqlx::FromRow, Debug)]
pub struct JobLookup {
pub job_id: String,
pub provider_id: Option<String>,
pub bpp_id: Option<String>,
pub bpp_uri: Option<String>,
}

pub struct NewJob {
pub job_id: String,
Expand Down Expand Up @@ -144,3 +160,37 @@ pub async fn deactivate_stale_jobs(

Ok(result.rows_affected())
}
pub async fn fetch_job_by_id(pool: &PgPool, job_id: Uuid) -> Result<JobRow, sqlx::Error> {
query_as::<_, JobRow>(
r#"
SELECT
id,
hash,
metadata,
beckn_structure
FROM jobs
WHERE id = $1
"#,
)
.bind(job_id)
.fetch_one(pool)
.await
}

pub async fn fetch_job_by_job_id(pool: &PgPool, job_id: &str) -> Result<JobLookup, sqlx::Error> {
query_as::<_, JobLookup>(
r#"
SELECT
job_id,
provider_id,
bpp_id,
bpp_uri
FROM jobs
WHERE job_id = $1
AND is_active = true
"#,
)
.bind(job_id)
.fetch_one(pool)
.await
}
54 changes: 1 addition & 53 deletions src/db/match_score.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
use crate::db::{job::JobRow, profiles::ProfileRow};
use serde_json::Value;
use sqlx::{query, query_as, query_scalar, FromRow, PgPool};
use uuid::Uuid;

#[derive(Debug, FromRow)]
pub struct JobRow {
pub id: Uuid,
pub hash: String,
pub metadata: Option<Value>,
pub beckn_structure: Option<Value>,
}

#[derive(Debug, FromRow)]
pub struct ProfileRow {
pub id: Uuid,
pub hash: String,
pub metadata: Option<Value>,
pub beckn_structure: Option<Value>,
}

#[derive(Debug, FromRow, Clone)]
pub struct JobLiteRow {
pub id: Uuid,
Expand Down Expand Up @@ -150,43 +135,6 @@ pub async fn upsert_match_score(
Ok(())
}

pub async fn fetch_job_by_id(pool: &PgPool, job_id: Uuid) -> Result<JobRow, sqlx::Error> {
query_as::<_, JobRow>(
r#"
SELECT
id,
hash,
metadata,
beckn_structure
FROM jobs
WHERE id = $1
"#,
)
.bind(job_id)
.fetch_one(pool)
.await
}

pub async fn fetch_profile_by_id(
pool: &PgPool,
profile_id: Uuid,
) -> Result<ProfileRow, sqlx::Error> {
query_as::<_, ProfileRow>(
r#"
SELECT
id,
hash,
metadata,
beckn_structure
FROM profiles
WHERE id = $1
"#,
)
.bind(profile_id)
.fetch_one(pool)
.await
}

pub async fn fetch_all_jobs(pool: &PgPool) -> Result<Vec<JobRow>, sqlx::Error> {
sqlx::query_as::<_, JobRow>(
r#"
Expand Down
99 changes: 96 additions & 3 deletions src/db/profiles.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
use crate::models::search::Pagination;
use crate::services::profiles::sync_profile_by_id;
use crate::state::AppState;
use axum::http::StatusCode;
use chrono::{DateTime, Utc};
use serde_json::Value;
use sqlx::{query, query_scalar, Error, PgPool, Row};
use serde_json::{json, Value};
use sqlx::{query, query_as, query_scalar, Error, FromRow, PgPool, Row};
use std::sync::Arc;
use tracing::info;

use uuid::Uuid;
pub struct PaginatedItems {
pub items: Vec<Value>,
pub total: i64,
}

#[derive(Debug, FromRow)]
pub struct ProfileRow {
pub id: Uuid,
pub hash: String,
pub metadata: Option<Value>,
pub beckn_structure: Option<Value>,
}

#[derive(FromRow, Debug)]
pub struct ProfileLookup {
pub profile_id: String,
pub metadata: serde_json::Value,
}
pub struct NewProfile {
pub profile_id: String,
pub user_id: String,
Expand Down Expand Up @@ -186,3 +203,79 @@ pub async fn fetch_beckn_profile_items(

Ok(PaginatedItems { items, total })
}

pub async fn fetch_profile_by_id(
pool: &PgPool,
profile_id: Uuid,
) -> Result<ProfileRow, sqlx::Error> {
query_as::<_, ProfileRow>(
r#"
SELECT
id,
hash,
metadata,
beckn_structure
FROM profiles
WHERE id = $1
"#,
)
.bind(profile_id)
.fetch_one(pool)
.await
}

pub async fn get_or_sync_profile(
state: &Arc<AppState>,
profile_id: &str,
) -> Result<ProfileLookup, (StatusCode, serde_json::Value)> {
let profile = query_as::<_, ProfileLookup>(
r#"
SELECT profile_id, metadata
FROM profiles
WHERE profile_id = $1
"#,
)
.bind(profile_id)
.fetch_optional(&state.db_pool)
.await
.map_err(|e| {
tracing::error!("DB error: {:?}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
json!({"error": "Database error"}),
)
})?;

if let Some(p) = profile {
return Ok(p);
}

if let Err(e) = sync_profile_by_id(state, profile_id).await {
tracing::error!("❌ Sync failed for {}: {:?}", profile_id, e);
}
let profile = query_as::<_, ProfileLookup>(
r#"
SELECT profile_id, metadata
FROM profiles
WHERE profile_id = $1
"#,
)
.bind(profile_id)
.fetch_optional(&state.db_pool)
.await
.map_err(|e| {
tracing::error!("DB error: {:?}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
json!({"error": "Database error"}),
)
})?;

if let Some(p) = profile {
return Ok(p);
}
Err((
StatusCode::NOT_FOUND,
json!({"error": "Invalid or missing profile_id"}),
))
}
6 changes: 5 additions & 1 deletion src/http/routes/job.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::services::job_apply::{handle_job_applications, handle_job_apply};
use crate::services::job_apply::{handle_job_applications, handle_job_apply, handle_job_apply_v2};
use crate::services::job_draft::{
create_user_draft_application, delete_user_draft_application, get_user_draft_applications,
update_user_draft_application,
Expand Down Expand Up @@ -29,5 +29,9 @@ pub fn routes(app_state: Arc<AppState>) -> Router {
"/v1/job-applications/drafts/{id}",
delete(delete_user_draft_application),
)
// ====================
// V2 APIs
// ====================
.route("/v2/apply", post(handle_job_apply_v2))
.with_state(app_state)
}
5 changes: 5 additions & 0 deletions src/models/job_apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ pub struct JobRequest {
pub context: MinimalContext,
pub message: InitMessage,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct JobApplyV2Request {
pub job_id: String,
pub profile_id: String,
}

pub type DraftRequest = JobRequest;
pub type JobApplyRequest = JobRequest;
Expand Down
Loading
Loading