Skip to content

Conversation

@swayam-agrahari
Copy link
Contributor

  • Added scheduled tasks to update CP ratings and insert attendance records daily at midnight.
  • Implemented API calls to fetch ratings from Codeforces and LeetCode.
  • Updated update_cp_ratings function to handle dynamic ratings based on platform.
  • Created placeholders for test configuration to avoid hardcoding sensitive data.
  • Added tests to validate rating updates for members with Codeforces and LeetCode profiles.

pub sex: String,
pub year: i32,
pub macaddress: String,
pub leaderboard_id: String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this used for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the username for their respective cp platform

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah gotcha, but they should be free to do both like i said not just 1 platform

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright so to implement this, we might need to create another leaderboard struct as this is one to many relation with foreign key as the member's id (primary key)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's right

pub year: i32,
pub macaddress: String,
pub leaderboard_id: String,
pub cp_platform: String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't members restricted to only one platform if we do it like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, they will be. I thought we were only allowed to choose one and given the current scenario, no one is trying for both.

Comment on lines +227 to +269
#[cfg(test)]
mod tests {
use super::*;

// Mocking the PgPool for testing purposes (if necessary)
use sqlx::PgPool;

#[tokio::test]
// Update these variables with the actual values before running the test

async fn test_fetch_codeforces_rating() {
let codeforces_username = ""; // Add your Codeforces username here
let result = fetch_codeforces_rating(codeforces_username).await;
assert!(result.is_ok());
let rating = result.unwrap();
assert!(rating.is_some());
}

#[tokio::test]
async fn test_fetch_leetcode_ranking() {
let leetcode_username = ""; // Add your LeetCode username here
let result = fetch_leetcode_ranking(leetcode_username).await;
assert!(result.is_ok());
let ranking = result.unwrap();
assert!(ranking.is_some());
}

#[tokio::test]
async fn test_scheduled_task() {
let database_url = ""; // Add your database URL here
let pool = Arc::new(PgPool::connect_lazy(database_url).unwrap());

scheduled_task(pool).await;
}

// Test for update_cp_ratings
#[tokio::test]
async fn test_update_cp_ratings() {
let database_url = ""; // Add your database URL here
let pool = Arc::new(PgPool::connect(database_url).await.unwrap());
update_cp_ratings(pool).await;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good to add tests but should be in a separate directory not in main.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sure will do it. I also thought about creating more tests for seeing members for dev purpose so this function can lie there.

Comment on lines +135 to +225
async fn fetch_codeforces_rating(
username: &str,
) -> Result<Option<i32>, Box<dyn std::error::Error>> {
let url = format!("https://codeforces.com/api/user.rating?handle={}", username);
let response = reqwest::get(&url).await?.text().await?;
let data: Value = serde_json::from_str(&response)?;

if data["status"] == "OK" {
if let Some(results) = data["result"].as_array() {
if let Some(last_contest) = results.last() {
let new_rating = last_contest["newRating"].as_i64().unwrap_or_default() as i32;
return Ok(Some(new_rating));
}
}
}
Ok(None)
}

// Function to fetch LeetCode ranking
async fn fetch_leetcode_ranking(username: &str) -> Result<Option<i32>, Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let url = "https://leetcode.com/graphql";
let query = r#"
query userPublicProfile($username: String!) {
matchedUser(username: $username) {
profile {
ranking
}
}
}
"#;

let response = client
.post(url)
.header("Content-Type", "application/json")
.json(&serde_json::json!({
"query": query,
"variables": {
"username": username
}
}))
.send()
.await?;

let data: Value = response.json().await?;
let ranking = data["data"]["matchedUser"]["profile"]["ranking"]
.as_i64()
.map(|v| v as i32);

Ok(ranking)
}

// Fetch and update CP ratings for all members
async fn update_cp_ratings(pool: Arc<PgPool>) {
let members: Result<Vec<Member>, sqlx::Error> =
sqlx::query_as::<_, Member>("SELECT * FROM Member")
.fetch_all(pool.as_ref())
.await;

match members {
Ok(members) => {
for member in members {
let rating = match member.cp_platform.as_str() {
"Codeforces" => fetch_codeforces_rating(&member.leaderboard_id)
.await
.ok()
.flatten(),
"LeetCode" => fetch_leetcode_ranking(&member.leaderboard_id)
.await
.ok()
.flatten(),
_ => None,
};

if let Some(rating) = rating {
let update_result = sqlx::query("UPDATE Member SET rating = $1 WHERE id = $2")
.bind(rating)
.bind(member.id)
.execute(pool.as_ref())
.await;

match update_result {
Ok(_) => println!("Updated rating for {}: {}", member.name, rating),
Err(e) => eprintln!("Failed to update rating for {}: {:?}", member.name, e),
}
}
}
}
Err(e) => eprintln!("Failed to fetch members: {:?}", e),
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single Leaderboard with Weighted Scores:
Combines scores from LeetCode and Codeforces into a unified ranking.

  • Pros: Simple, gives a balanced view, and avoids splitting attention.
    
  • Cons: Needs agreement on weightage and a formula to merge scores fairly.
    

Separate Leaderboards:
Maintains distinct rankings for each platform.

  • Pros: Highlights specific performance on each platform.
    
  • Cons: Can feel redundant or less competitive if interest skews heavily toward one platform
    

can you ask in discord which is preferred? make sure to highlite these pros and cons

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes done : )

@swayam-agrahari swayam-agrahari closed this by deleting the head repository Dec 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants