From 21004e9be98a647459946110361d097968adf159 Mon Sep 17 00:00:00 2001 From: hkx05 Date: Tue, 26 Nov 2024 21:40:25 +0530 Subject: [PATCH 1/3] feat: implemented streaks --- migrations/20241126123155_adding_streaks.sql | 2 + src/db/member.rs | 2 + src/graphql/mutations.rs | 50 +++++++++++++++++++- src/graphql/query.rs | 14 ++++++ 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 migrations/20241126123155_adding_streaks.sql diff --git a/migrations/20241126123155_adding_streaks.sql b/migrations/20241126123155_adding_streaks.sql new file mode 100644 index 0000000..11f8e60 --- /dev/null +++ b/migrations/20241126123155_adding_streaks.sql @@ -0,0 +1,2 @@ +ALTER TABLE Member ADD COLUMN streak INT; +ALTER TABLE Member ADD COLUMN max_streak INT; \ No newline at end of file diff --git a/src/db/member.rs b/src/db/member.rs index 4bdce7d..5cfaa78 100644 --- a/src/db/member.rs +++ b/src/db/member.rs @@ -15,4 +15,6 @@ pub struct Member { pub year: i32, pub macaddress: String, pub discord_id: Option, + pub streak: Option, + pub max_streak: Option, } diff --git a/src/graphql/mutations.rs b/src/graphql/mutations.rs index b3f6d41..30d0575 100644 --- a/src/graphql/mutations.rs +++ b/src/graphql/mutations.rs @@ -104,7 +104,6 @@ impl MutationRoot { mac.update(message.as_bytes()); let expected_signature = mac.finalize().into_bytes(); - // Convert the received HMAC signature from the client to bytes for comparison let received_signature = hex::decode(hmac_signature) @@ -138,4 +137,51 @@ impl MutationRoot { Ok(attendance) } -} + async fn update_streak( + &self, + ctx: &Context<'_>, + id: i32, + has_sent_update: bool, + ) -> Result { + let pool = ctx.data::>().expect("Pool not found in context"); + + let member = sqlx::query_as::<_, Member>( + " + SELECT streak, max_streak + FROM Member + WHERE id = $1 + " + ) + .bind(id) + .fetch_one(pool.as_ref()) + .await?; + + let current_streak = member.streak.unwrap_or(0); + let max_streak = member.max_streak.unwrap_or(0); + + let (new_streak, new_max_streak) = if has_sent_update { + let updated_streak = current_streak + 1; + let updated_max_streak = (updated_streak).max(max_streak); + (updated_streak, updated_max_streak) + }else{ + (0, max_streak) + }; + + let updated_member = sqlx::query_as::<_, Member>( + " + UPDATE Member + SET streak = $1, max_streak = $2 + WHERE id = $3 + RETURNING * + " + ) + + .bind(new_streak) + .bind(new_max_streak) + .bind(id) + .fetch_one(pool.as_ref()) + .await?; + + Ok(updated_member) + } +} \ No newline at end of file diff --git a/src/graphql/query.rs b/src/graphql/query.rs index 07120e9..dd917ab 100644 --- a/src/graphql/query.rs +++ b/src/graphql/query.rs @@ -36,4 +36,18 @@ impl QueryRoot { .await?; Ok(attendance_list) } + //Query for retrieving the streaks + async fn get_streak( + &self, + ctx: &Context<'_>, + ) -> Result, sqlx::Error> { + let pool = ctx.data::>().expect("Pool not found in context"); + + let streak_list = sqlx::query_as::<_, Member>( + "SELECT id, name, streak, max_streak FROM Member" + ) + .fetch_all(pool.as_ref()) + .await?; + Ok(streak_list) + } } From 2c7bac777217b28ffe865a34333d38e00262d74b Mon Sep 17 00:00:00 2001 From: hkx05 Date: Tue, 26 Nov 2024 22:19:24 +0530 Subject: [PATCH 2/3] mutation and query for group id --- migrations/20241126162522_add_member_group.sql | 1 + src/db/member.rs | 1 + src/graphql/mutations.rs | 13 +++++++++---- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 migrations/20241126162522_add_member_group.sql diff --git a/migrations/20241126162522_add_member_group.sql b/migrations/20241126162522_add_member_group.sql new file mode 100644 index 0000000..f95c6e2 --- /dev/null +++ b/migrations/20241126162522_add_member_group.sql @@ -0,0 +1 @@ +ALTER TABLE Member ADD COLUMN group_id INT; \ No newline at end of file diff --git a/src/db/member.rs b/src/db/member.rs index 5cfaa78..ec30b42 100644 --- a/src/db/member.rs +++ b/src/db/member.rs @@ -17,4 +17,5 @@ pub struct Member { pub discord_id: Option, pub streak: Option, pub max_streak: Option, + pub group_id: Option, } diff --git a/src/graphql/mutations.rs b/src/graphql/mutations.rs index c29ce10..ec013ef 100644 --- a/src/graphql/mutations.rs +++ b/src/graphql/mutations.rs @@ -30,6 +30,7 @@ impl MutationRoot { year: i32, macaddress: String, discord_id: String, + group_id: i32, ) -> Result { let pool = ctx.data::>().expect("Pool not found in context"); @@ -37,7 +38,7 @@ impl MutationRoot { let member = sqlx::query_as::<_, Member>( - "INSERT INTO Member (rollno, name, hostel, email, sex, year, macaddress, discord_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *" + "INSERT INTO Member (rollno, name, hostel, email, sex, year, macaddress, discord_id, group_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *" ) .bind(rollno) .bind(name) @@ -47,6 +48,7 @@ impl MutationRoot { .bind(year) .bind(macaddress) .bind(discord_id) + .bind(group_id) .fetch_one(pool.as_ref()) .await?; @@ -61,6 +63,7 @@ impl MutationRoot { year: i32, macaddress: String, discord_id: String, + group_id: i32, hmac_signature: String, ) -> Result { let pool = ctx.data::>().expect("Pool not found in context"); @@ -69,7 +72,7 @@ impl MutationRoot { let mut mac = HmacSha256::new_from_slice(secret_key.as_bytes()).expect("HMAC can take key of any size"); - let message = format!("{}{}{}{}{}", id, hostel, year, macaddress, discord_id); + let message = format!("{}{}{}{}{}{}", id, hostel, year, macaddress, discord_id, group_id); mac.update(message.as_bytes()); let expected_signature = mac.finalize().into_bytes(); @@ -91,8 +94,9 @@ impl MutationRoot { hostel = CASE WHEN $1 = '' THEN hostel ELSE $1 END, year = CASE WHEN $2 = 0 THEN year ELSE $2 END, macaddress = CASE WHEN $3 = '' THEN macaddress ELSE $3 END, - discord_id = CASE WHEN $4 = '' THEN discord_id ELSE $4 END - WHERE id = $5 + discord_id = CASE WHEN $4 = '' THEN discord_id ELSE $4 END, + group_id = CASE WHEN $5 = 0 THEN group_id ELSE $5 END + WHERE id = $6 RETURNING * " ) @@ -101,6 +105,7 @@ impl MutationRoot { .bind(year) .bind(macaddress) .bind(discord_id) + .bind(group_id) .bind(id) .fetch_one(pool.as_ref()) .await?; From e845df10f31bb26dd238c086a9d0da4c595b561f Mon Sep 17 00:00:00 2001 From: hkx05 Date: Sat, 30 Nov 2024 02:28:41 +0530 Subject: [PATCH 3/3] fixed all errors --- .../20241128224140_add_streak_relation.sql | 6 ++ ...9193435_remove_streks_from_membertable.sql | 3 + .../20241129195135_add_streaks_table.sql | 6 ++ .../20241129195234_drop_old_streak_table.sql | 1 + .../20241129200327_drop_strek_update.sql | 1 + .../20241129200519_recreate_streaks.sql | 6 ++ src/db/member.rs | 9 +- src/graphql/mutations.rs | 83 +++++++++++-------- src/graphql/query.rs | 17 ++-- 9 files changed, 88 insertions(+), 44 deletions(-) create mode 100644 migrations/20241128224140_add_streak_relation.sql create mode 100644 migrations/20241129193435_remove_streks_from_membertable.sql create mode 100644 migrations/20241129195135_add_streaks_table.sql create mode 100644 migrations/20241129195234_drop_old_streak_table.sql create mode 100644 migrations/20241129200327_drop_strek_update.sql create mode 100644 migrations/20241129200519_recreate_streaks.sql diff --git a/migrations/20241128224140_add_streak_relation.sql b/migrations/20241128224140_add_streak_relation.sql new file mode 100644 index 0000000..e42db4c --- /dev/null +++ b/migrations/20241128224140_add_streak_relation.sql @@ -0,0 +1,6 @@ +CREATE TABLE Streaks ( + id SERIAL PRIMARY KEY, + streak INT NOT NULL DEFAULT 0, + max_streak INT NOT NULL DEFAULT 0, + FOREIGN KEY (id) REFERENCES Member(id) ON DELETE CASCADE +); \ No newline at end of file diff --git a/migrations/20241129193435_remove_streks_from_membertable.sql b/migrations/20241129193435_remove_streks_from_membertable.sql new file mode 100644 index 0000000..a147905 --- /dev/null +++ b/migrations/20241129193435_remove_streks_from_membertable.sql @@ -0,0 +1,3 @@ +ALTER TABLE Member +DROP COLUMN streak, +DROP COLUMN max_streak; \ No newline at end of file diff --git a/migrations/20241129195135_add_streaks_table.sql b/migrations/20241129195135_add_streaks_table.sql new file mode 100644 index 0000000..36fe370 --- /dev/null +++ b/migrations/20241129195135_add_streaks_table.sql @@ -0,0 +1,6 @@ +CREATE TABLE StreakUpdate ( + id SERIAL PRIMARY KEY, + streak INT NOT NULL DEFAULT 0, + max_streak INT NOT NULL DEFAULT 0, + FOREIGN KEY (id) REFERENCES Member(id) ON DELETE CASCADE +); \ No newline at end of file diff --git a/migrations/20241129195234_drop_old_streak_table.sql b/migrations/20241129195234_drop_old_streak_table.sql new file mode 100644 index 0000000..18f205d --- /dev/null +++ b/migrations/20241129195234_drop_old_streak_table.sql @@ -0,0 +1 @@ +DROP TABLE Streaks; \ No newline at end of file diff --git a/migrations/20241129200327_drop_strek_update.sql b/migrations/20241129200327_drop_strek_update.sql new file mode 100644 index 0000000..4193851 --- /dev/null +++ b/migrations/20241129200327_drop_strek_update.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS StreakUpdate; \ No newline at end of file diff --git a/migrations/20241129200519_recreate_streaks.sql b/migrations/20241129200519_recreate_streaks.sql new file mode 100644 index 0000000..36fe370 --- /dev/null +++ b/migrations/20241129200519_recreate_streaks.sql @@ -0,0 +1,6 @@ +CREATE TABLE StreakUpdate ( + id SERIAL PRIMARY KEY, + streak INT NOT NULL DEFAULT 0, + max_streak INT NOT NULL DEFAULT 0, + FOREIGN KEY (id) REFERENCES Member(id) ON DELETE CASCADE +); \ No newline at end of file diff --git a/src/db/member.rs b/src/db/member.rs index ec30b42..3306336 100644 --- a/src/db/member.rs +++ b/src/db/member.rs @@ -15,7 +15,12 @@ pub struct Member { pub year: i32, pub macaddress: String, pub discord_id: Option, - pub streak: Option, - pub max_streak: Option, pub group_id: Option, } + +#[derive(FromRow, SimpleObject)] +pub struct StreakUpdate { + pub id: i32, + pub streak: Option, + pub max_streak: Option, +} \ No newline at end of file diff --git a/src/graphql/mutations.rs b/src/graphql/mutations.rs index ec013ef..bb39536 100644 --- a/src/graphql/mutations.rs +++ b/src/graphql/mutations.rs @@ -11,7 +11,7 @@ use sha2::Sha256; type HmacSha256 = Hmac; -use crate::db::{member::Member, attendance::Attendance}; +use crate::db::{member::Member, attendance::Attendance, member::StreakUpdate}; pub struct MutationRoot; @@ -201,46 +201,63 @@ impl MutationRoot { ctx: &Context<'_>, id: i32, has_sent_update: bool, - ) -> Result { + ) -> Result { let pool = ctx.data::>().expect("Pool not found in context"); - let member = sqlx::query_as::<_, Member>( + let streak_info = sqlx::query_as::<_, StreakUpdate>( " - SELECT streak, max_streak - FROM Member + SELECT id, streak, max_streak + FROM StreakUpdate WHERE id = $1 " ) .bind(id) - .fetch_one(pool.as_ref()) - .await?; - - let current_streak = member.streak.unwrap_or(0); - let max_streak = member.max_streak.unwrap_or(0); - - let (new_streak, new_max_streak) = if has_sent_update { - let updated_streak = current_streak + 1; - let updated_max_streak = (updated_streak).max(max_streak); - (updated_streak, updated_max_streak) - }else{ - (0, max_streak) - }; - - let updated_member = sqlx::query_as::<_, Member>( - " - UPDATE Member - SET streak = $1, max_streak = $2 - WHERE id = $3 - RETURNING * - " - ) - - .bind(new_streak) - .bind(new_max_streak) - .bind(id) - .fetch_one(pool.as_ref()) + .fetch_optional(pool.as_ref()) .await?; - Ok(updated_member) + match streak_info{ + Some(mut member) => { + let current_streak = member.streak.unwrap_or(0); + let max_streak = member.max_streak.unwrap_or(0); + let (new_streak, new_max_streak) = if has_sent_update { + let updated_streak = current_streak + 1; + let updated_max_streak = updated_streak.max(max_streak); + (updated_streak, updated_max_streak) + } else { + (0, max_streak) + }; + let updated_member = sqlx::query_as::<_, StreakUpdate>( + " + UPDATE StreakUpdate + SET streak = $1, max_streak = $2 + WHERE id = $3 + RETURNING * + " + ) + .bind(new_streak) + .bind(new_max_streak) + .bind(id) + .fetch_one(pool.as_ref()) + .await?; + + Ok(updated_member) + }, + None => { + let new_member = sqlx::query_as::<_, StreakUpdate>( + " + INSERT INTO StreakUpdate (id, streak, max_streak) + VALUES ($1, $2, $3) + RETURNING * + " + ) + .bind(id) + .bind(0) + .bind(0) + .fetch_one(pool.as_ref()) + .await?; + + Ok(new_member) + } + } } } \ No newline at end of file diff --git a/src/graphql/query.rs b/src/graphql/query.rs index dd917ab..cc84fe8 100644 --- a/src/graphql/query.rs +++ b/src/graphql/query.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use chrono::NaiveDate; -use crate::db::{member::Member, attendance::Attendance}; +use crate::db::{member::Member, attendance::Attendance, member::StreakUpdate}; pub struct QueryRoot; @@ -36,18 +36,17 @@ impl QueryRoot { .await?; Ok(attendance_list) } - //Query for retrieving the streaks async fn get_streak( &self, ctx: &Context<'_>, - ) -> Result, sqlx::Error> { + id: i32, + ) -> Result { let pool = ctx.data::>().expect("Pool not found in context"); - - let streak_list = sqlx::query_as::<_, Member>( - "SELECT id, name, streak, max_streak FROM Member" - ) - .fetch_all(pool.as_ref()) + let streak = sqlx::query_as::<_, StreakUpdate>("SELECT * FROM StreakUpdate WHERE id = $1") + .bind(id) + .fetch_one(pool.as_ref()) .await?; - Ok(streak_list) + + Ok(streak) } }