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

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

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

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

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

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

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

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

2 changes: 2 additions & 0 deletions backend/migrations/007_add_linkedin_account.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS linkedin_account TEXT;
CREATE UNIQUE INDEX IF NOT EXISTS unique_linkedin_account_lower ON profiles (LOWER(linkedin_account));
27 changes: 27 additions & 0 deletions backend/src/application/commands/create_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::application::dtos::profile_dtos::{CreateProfileRequest, ProfileRespon
use crate::domain::entities::profile::Profile;
use crate::domain::repositories::profile_repository::ProfileRepository;
use crate::domain::value_objects::wallet_address::WalletAddress;
use regex;
use std::sync::Arc;

pub async fn create_profile(
Expand All @@ -24,6 +25,31 @@ pub async fn create_profile(
let mut profile = Profile::new(wallet_address.clone());
profile.update_info(Some(request.name), request.description, request.avatar_url);

if let Some(ref account) = request.linkedin_account {
let trimmed = account.trim();

if trimmed.is_empty() {
profile.linkedin_account = None;
} else {
let valid_format = regex::Regex::new(r"^[a-zA-Z0-9-]{3,100}$").unwrap();
if !valid_format.is_match(trimmed) {
return Err("Invalid LinkedIn account format".to_string());
}

let normalized = trimmed.to_lowercase();
if profile_repository
.find_by_linkedin_account(normalized.as_str())
.await
.map_err(|e| e.to_string())?
.is_some()
{
return Err("LinkedIn account already taken".to_string());
}

profile.linkedin_account = Some(trimmed.to_string());
}
}

profile_repository
.create(&profile)
.await
Expand All @@ -36,6 +62,7 @@ pub async fn create_profile(
avatar_url: profile.avatar_url,
github_login: profile.github_login,
twitter_handle: profile.twitter_handle,
linkedin_account: profile.linkedin_account,
created_at: profile.created_at,
updated_at: profile.updated_at,
})
Expand Down
28 changes: 28 additions & 0 deletions backend/src/application/commands/update_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,33 @@ pub async fn update_profile(
profile.twitter_handle = Some(trimmed.to_string());
}
}
if let Some(ref account) = request.linkedin_account {
let trimmed = account.trim();

// Allow empty accounts (set to None)
if trimmed.is_empty() {
profile.linkedin_account = None;
} else {
// Validate format for non-empty LinkedIn accounts
let valid_format = regex::Regex::new(r"^[a-zA-Z0-9-]{3,100}$").unwrap();
if !valid_format.is_match(trimmed) {
return Err("Invalid LinkedIn account format".to_string());
}

let normalized = trimmed.to_lowercase();
if let Some(conflicting_profile) = profile_repository
.find_by_linkedin_account(normalized.as_str())
.await
.map_err(|e| e.to_string())?
{
if conflicting_profile.address != wallet_address {
return Err("LinkedIn account already taken".to_string());
}
}

profile.linkedin_account = Some(trimmed.to_string());
}
}
profile_repository
.update(&profile)
.await
Expand All @@ -80,6 +107,7 @@ pub async fn update_profile(
avatar_url: profile.avatar_url,
github_login: profile.github_login,
twitter_handle: profile.twitter_handle,
linkedin_account: profile.linkedin_account,
created_at: profile.created_at,
updated_at: profile.updated_at,
})
Expand Down
3 changes: 3 additions & 0 deletions backend/src/application/dtos/profile_dtos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct CreateProfileRequest {
pub name: String,
pub description: Option<String>,
pub avatar_url: Option<String>,
pub linkedin_account: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand All @@ -16,6 +17,7 @@ pub struct UpdateProfileRequest {
pub avatar_url: Option<String>,
pub github_login: Option<String>,
pub twitter_handle: Option<String>,
pub linkedin_account: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand All @@ -26,6 +28,7 @@ pub struct ProfileResponse {
pub avatar_url: Option<String>,
pub github_login: Option<String>,
pub twitter_handle: Option<String>,
pub linkedin_account: Option<String>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
1 change: 1 addition & 0 deletions backend/src/application/queries/get_all_profiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub async fn get_all_profiles(
avatar_url: profile.avatar_url,
github_login: profile.github_login,
twitter_handle: profile.twitter_handle,
linkedin_account: profile.linkedin_account,
created_at: profile.created_at,
updated_at: profile.updated_at,
})
Expand Down
1 change: 1 addition & 0 deletions backend/src/application/queries/get_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub async fn get_profile(
avatar_url: profile.avatar_url,
github_login: profile.github_login,
twitter_handle: profile.twitter_handle,
linkedin_account: profile.linkedin_account,
created_at: profile.created_at,
updated_at: profile.updated_at,
})
Expand Down
Loading
Loading