diff --git a/.sqlx/query-8688ce34277d10e20b2ee3cd3e92d8791708804985fa2ce83167cc69ea71b484.json b/.sqlx/query-8688ce34277d10e20b2ee3cd3e92d8791708804985fa2ce83167cc69ea71b484.json new file mode 100644 index 0000000..ad9bfee --- /dev/null +++ b/.sqlx/query-8688ce34277d10e20b2ee3cd3e92d8791708804985fa2ce83167cc69ea71b484.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM teacher_oauths\n WHERE\n teacher = $1 AND\n provider = $2;\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Text" + ] + }, + "nullable": [] + }, + "hash": "8688ce34277d10e20b2ee3cd3e92d8791708804985fa2ce83167cc69ea71b484" +} diff --git a/.sqlx/query-c89b2f9eb5f176a580078974cadd705d9b1b0848158f85a96f33fbf2818563d1.json b/.sqlx/query-c89b2f9eb5f176a580078974cadd705d9b1b0848158f85a96f33fbf2818563d1.json new file mode 100644 index 0000000..ebbe1ee --- /dev/null +++ b/.sqlx/query-c89b2f9eb5f176a580078974cadd705d9b1b0848158f85a96f33fbf2818563d1.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT teacher as id\n FROM teacher_oauths\n WHERE\n provider = $1 AND\n sub = $2;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c89b2f9eb5f176a580078974cadd705d9b1b0848158f85a96f33fbf2818563d1" +} diff --git a/.sqlx/query-fc950d55a77a8917bae2e0ac738764a90412eeee3fcdcd3b77afc609f557f6b2.json b/.sqlx/query-fc950d55a77a8917bae2e0ac738764a90412eeee3fcdcd3b77afc609f557f6b2.json new file mode 100644 index 0000000..59ca2e7 --- /dev/null +++ b/.sqlx/query-fc950d55a77a8917bae2e0ac738764a90412eeee3fcdcd3b77afc609f557f6b2.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO teacher_oauths (teacher, provider, sub)\n VALUES ($1, $2, $3);\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Varchar", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "fc950d55a77a8917bae2e0ac738764a90412eeee3fcdcd3b77afc609f557f6b2" +} diff --git a/sql_schema.txt b/sql_schema.txt deleted file mode 100644 index fde4df1..0000000 --- a/sql_schema.txt +++ /dev/null @@ -1,16 +0,0 @@ -teachers: - teacherid: (PRIMARY !NULL) uuid - teachername: (UNIQUE !NULL) varchar(255) - - isabsent: ( !NULL) bool - fullyabsent: ( !NULL) bool - -teachers_periods_absence_xref: - teacherid: (FOREIGN REFERENCES teacher(teacherid) !NULL) uuid - periodid: (FOREIGN REFERENCES period (periodid ) !NULL) uuid - - (PRIMARY KEY CONSTRAINT (teacherid, periodid)) - -periods: - periodid: (PRIMARY !NULL) uuid - periodname: (UNIQUE !NULL) varchar(255) diff --git a/sql_schemas/v8/down.sql b/sql_schemas/v8/down.sql new file mode 100644 index 0000000..5585717 --- /dev/null +++ b/sql_schemas/v8/down.sql @@ -0,0 +1 @@ +DROP TABLE teacher_oauths; diff --git a/sql_schemas/v8/up.sql b/sql_schemas/v8/up.sql new file mode 100644 index 0000000..c4eb7cb --- /dev/null +++ b/sql_schemas/v8/up.sql @@ -0,0 +1,7 @@ +CREATE TABLE teacher_oauths ( + teacher uuid NOT NULL REFERENCES teachers(id) ON DELETE CASCADE, + provider varchar(63) NOT NULL, + sub varchar(255) NOT NULL, + + CONSTRAINT unique_sub_for_provider UNIQUE (teacher, provider) +); diff --git a/src/database/prepared/teacher.rs b/src/database/prepared/teacher.rs index 84b6eb0..45b07d3 100644 --- a/src/database/prepared/teacher.rs +++ b/src/database/prepared/teacher.rs @@ -118,53 +118,6 @@ pub async fn get_all_teachers(ctx: &mut Ctx) -> Result, sqlx::Error } -// pub async fn update_chall(ctx: &mut Ctx, id: Uuid, input: ChallInput) -> Result, sqlx::Error> { -// let query = query!( -// r#" -// UPDATE challenges -// SET -// name = COALESCE($2, name), -// description = COALESCE($3, description), -// points = COALESCE($4, points), -// authors = COALESCE($5, authors), -// hints = COALESCE($6, hints), -// categories = COALESCE($7, categories), -// tags = COALESCE($8, tags), -// visible = COALESCE($9, visible), -// source_folder = COALESCE($10, source_folder) -// WHERE id = $1; -// "#, -// id, -// input.name: String, -// input.description, -// input.points, -// input.authors.as_deref(), -// input.hints.as_deref(), -// input.categories.as_deref(), -// input.tags.as_deref(), -// input.visible, -// input.source_folder, -// ); -// let affected = query -// .execute(&mut *ctx) -// .await? -// .rows_affected(); - -// if affected != 1 { return Ok(None) } - -// if let Some(links) = input.links { -// set_chall_links(&mut *ctx, id, links).await?; -// } -// set_chall_updated(&mut *ctx, id).await?; - -// let Some(output) = get_chall(ctx, id).await? else { -// return Err(sqlx::Error::RowNotFound); -// }; - -// Ok(Some(output)) -// } - - struct Id { id: Uuid } @@ -332,3 +285,57 @@ pub async fn update_teacher_full_absence(ctx: &mut Ctx, id: Uuid, fully_absent: get_teacher(ctx, id).await } + + + +pub async fn get_teacher_by_oauth(ctx: &mut Ctx, provider: String, sub: String) -> Result { + let teacher_oauth_query = query_as!( + Id, + r#" + SELECT teacher as id + FROM teacher_oauths + WHERE + provider = $1 AND + sub = $2; + "#, + provider, + sub, + ); + + let teacher_id: Id = teacher_oauth_query.fetch_one(&mut **ctx).await?; + + get_teacher(ctx, teacher_id.id).await +} + +pub async fn add_teacher_oauth(ctx: &mut Ctx, teacher: Uuid, provider: String, sub: String) -> Result<(), sqlx::Error> { + let add_teacher_oauth = query!( + r#" + INSERT INTO teacher_oauths (teacher, provider, sub) + VALUES ($1, $2, $3); + "#, + teacher, + provider, + sub, + ); + + add_teacher_oauth.execute(&mut **ctx).await?; + + Ok(()) +} + +pub async fn remove_teacher_oauth(ctx: &mut Ctx, teacher: Uuid, provider: String) -> Result<(), sqlx::Error> { + let remove_teacher_oauth = query!( + r#" + DELETE FROM teacher_oauths + WHERE + teacher = $1 AND + provider = $2; + "#, + teacher, + provider, + ); + + remove_teacher_oauth.execute(&mut **ctx).await?; + + Ok(()) +} diff --git a/src/graphql/resolvers/mutation/mod.rs b/src/graphql/resolvers/mutation/mod.rs index f27ff9f..75fc571 100755 --- a/src/graphql/resolvers/mutation/mod.rs +++ b/src/graphql/resolvers/mutation/mod.rs @@ -173,6 +173,73 @@ impl MutationRoot { }) } + async fn add_teacher_associated_oauth( + &self, + ctx_accessor: &Context<'_>, + id: Uuid, + provider: String, + sub: String, + ) -> GraphQlResult { + use crate::database::prepared::teacher::add_teacher_oauth as add_teacher_associated_oauth_in_db; + + let ctx = ctx_accessor.data::()?; + + let mut db_conn = ctx.db() + .acquire() + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Could not open connection to the database: {e}")) + })?; + + add_teacher_associated_oauth_in_db(&mut db_conn, id, provider, sub) + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Database error: {e}")) + })?; + + get_teacher(&mut db_conn, id) + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Database error: {e}")) + }) + } + + async fn remove_teacher_associated_oauth( + &self, + ctx_accessor: &Context<'_>, + id: Uuid, + provider: String, + ) -> GraphQlResult { + use crate::database::prepared::teacher::remove_teacher_oauth as remove_teacher_associated_oauth_in_db; + + let ctx = ctx_accessor.data::()?; + + let mut db_conn = ctx.db() + .acquire() + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Could not open connection to the database: {e}")) + })?; + + remove_teacher_associated_oauth_in_db(&mut db_conn, id, provider) + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Database error: {e}")) + })?; + + get_teacher(&mut db_conn, id) + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Database error: {e}")) + }) + } + // async fn delete_teacher( // ctx: &Context, // id: TeacherId, diff --git a/src/graphql/resolvers/query.rs b/src/graphql/resolvers/query.rs index 8c105eb..fc9cec8 100755 --- a/src/graphql/resolvers/query.rs +++ b/src/graphql/resolvers/query.rs @@ -54,7 +54,7 @@ impl QueryRoot { .await .map_err(|e| { let e = e.to_string(); - GraphQlError::new(format!("Failed to get teachers from database {e}")) + GraphQlError::new(format!("Failed to get teacher from database {e}")) }) } @@ -89,6 +89,32 @@ impl QueryRoot { }) } + async fn get_teacher_by_oauth( + &self, + ctx_accessor: &Context<'_>, + #[graphql(desc = "Provider of OAuth")] provider: String, + #[graphql(desc = "Sub of OAuth")] sub: String, + ) -> GraphQlResult { + use crate::database::prepared::teacher::get_teacher_by_oauth as get_teacher_by_oauth_from_db; + + let ctx = ctx_accessor.data::()?; + + let mut db_conn = ctx.db() + .acquire() + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Could not open connection to the database {e}")) + })?; + + get_teacher_by_oauth_from_db(&mut db_conn, provider, sub) + .await + .map_err(|e| { + let e = e.to_string(); + GraphQlError::new(format!("Failed to get teacher from database {e}")) + }) + } + async fn all_periods( &self, ctx: &Context<'_>,