From 1e20b53af7be2778fd8109d6f836b810acb2f919 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Sun, 11 Feb 2024 13:31:50 -0600 Subject: [PATCH 01/11] Efficient query for students --- LearningAPI.session.sql | 346 +++++++++++++++++++++++++++++++ LearningAPI/views/course_view.py | 11 +- 2 files changed, 356 insertions(+), 1 deletion(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 25a9a05..2a47337 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -247,3 +247,349 @@ ORDER BY book.index, project.index ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +DROP FUNCTION IF EXISTS get_student_details(INT); + + +select * from get_student_details(207); -- No assessment +select * from get_student_details(176); -- In progress +select * from get_student_details(205); -- Completed assessment + + + + +CREATE OR REPLACE FUNCTION get_student_details(student_user_id INT) +RETURNS TABLE ( + full_name TEXT, + project_id INT, + project_index INT, + latest_project_name TEXT, + book_id INT, + book_index INT, + latest_book_name TEXT, + current_cohort_name TEXT, + current_cohort_start_date DATE, + current_cohort_end_date DATE, + assessment_status_id INT, + assessment_status TEXT, + total_score INT +) AS $$ +BEGIN + RETURN QUERY + WITH student_info AS ( + SELECT + au.id, + au.first_name || ' ' || au.last_name AS full_name + FROM auth_user au + WHERE au.id = student_user_id + ), + latest_project AS ( + SELECT + sp.student_id, + p.id AS project_id, + p.index AS project_index, + p.name AS project_name, + b.id AS book_id, + b.index AS book_index, + b.name AS book_name, + sp.date_created + FROM "LearningAPI_studentproject" sp + JOIN "LearningAPI_project" p ON sp.project_id = p.id + JOIN "LearningAPI_book" b ON p.book_id = b.id + WHERE sp.student_id = student_user_id + ORDER BY sp.date_created DESC + LIMIT 1 + ), + current_cohort AS ( + SELECT + nuc.nss_user_id, + c.name AS cohort_name, + c.start_date, + c.end_date + FROM "LearningAPI_nssusercohort" nuc + JOIN "LearningAPI_cohort" c ON nuc.cohort_id = c.id + WHERE nuc.nss_user_id = student_user_id + ORDER BY nuc.id DESC + LIMIT 1 + ), + assessment_status_agg AS ( + SELECT + sa.student_id, + sa.assessment_id, + sa.status_id, + CASE + WHEN sa.status_id = 1 THEN 'In Progress' + WHEN sa.status_id = 2 THEN 'Ready for Review' + WHEN sa.status_id = 3 THEN 'Reviewed and Incomplete' + WHEN sa.status_id = 4 THEN 'Reviewed and Complete' + ELSE 'Unknown' + END AS status + FROM "LearningAPI_studentassessment" sa + JOIN latest_project lp ON sa.student_id = lp.student_id + JOIN "LearningAPI_assessment" a ON sa.assessment_id = a.id AND a.book_id = lp.book_id + WHERE sa.student_id = student_user_id + ORDER BY sa.date_created DESC + LIMIT 1 + ), + score_calc AS ( + SELECT + lr.student_id, + SUM(lw.weight) AS total_score + FROM "LearningAPI_learningrecord" lr + JOIN "LearningAPI_learningweight" lw ON lr.weight_id = lw.id + WHERE lr.student_id = student_user_id AND lr.achieved = TRUE + GROUP BY lr.student_id + ) + SELECT + si.full_name::text, + lp.project_id::int AS project_id, + lp.project_index::int AS project_index, + lp.project_name::text AS latest_project_name, + lp.book_id::int AS book_id, + lp.book_index::int AS book_index, + lp.book_name::text AS latest_book_name, + cc.cohort_name::text AS current_cohort_name, + cc.start_date::date AS current_cohort_start_date, + cc.end_date::date AS current_cohort_end_date, + coalesce(asa.status_id::int, 0)::int AS assessment_status_id, + coalesce(asa.status::text, 'Not Available')::text AS assessment_status, + coalesce(sc.total_score::int, 0)::int AS total_score + FROM student_info si + LEFT JOIN latest_project lp ON si.id = lp.student_id + LEFT JOIN current_cohort cc ON si.id = cc.nss_user_id + LEFT JOIN assessment_status_agg asa ON si.id = asa.student_id + LEFT JOIN score_calc sc ON si.id = sc.student_id; +END; $$ +LANGUAGE plpgsql; + + + + + + + + + + + + + + + + + + + + + + + + + + + + +select * from get_student_details(207); -- No assessment +select * from get_student_details(176); -- In progress +select * from get_student_details(205); -- Completed assessment + + + + +SELECT + nu.user_id, + nu.github_handle, + au."first_name" || ' ' || au."last_name" AS name, + sa.status_id AS assessment_status_id, + sp."project_id" AS project_id, + p.index AS project_index, + p."name" AS project_name, + b.id AS book_id, + b.index AS book_index, + b.name AS book_name, + lr.total_score AS score + FROM "LearningAPI_nssuser" nu + JOIN "auth_user" au ON au."id" = nu."user_id" + JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" + JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" + LEFT JOIN "LearningAPI_studentproject" sp + ON sp."student_id" = nu."id" + AND sp."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentproject" + WHERE "student_id" = nu."id" + ) + LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" + LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" + LEFT JOIN "LearningAPI_assessment" la + ON b.id = la.book_id + LEFT JOIN "LearningAPI_studentassessment" sa + ON sa."student_id" = nu."id" + AND sa."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentassessment" + WHERE "student_id" = nu."id" + ) + AND sa.assessment_id = la.id + LEFT JOIN ( + SELECT lr."student_id", SUM(lw."weight") AS total_score + FROM "LearningAPI_learningrecord" lr + JOIN "LearningAPI_learningrecordentry" lre ON lre."record_id" = lr."id" + JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" + WHERE lr."achieved" = true + GROUP BY lr."student_id" + ) lr ON lr."student_id" = nu."id" + WHERE nc."cohort_id" = 11 + ORDER BY b.index ASC, + p.index ASC; + + + + + +DROP FUNCTION IF EXISTS get_cohort_student_details(INT); + +select * from get_cohort_student_details(11); -- No assessment + + + +CREATE OR REPLACE FUNCTION get_cohort_student_details(student_cohort_id INT) +RETURNS TABLE ( + full_name TEXT, + project_id INT, + project_index INT, + latest_project_name TEXT, + book_id INT, + book_index INT, + latest_book_name TEXT, + current_cohort_name TEXT, + current_cohort_start_date DATE, + current_cohort_end_date DATE, + assessment_status_id INT, + assessment_status TEXT, + total_score INT +) AS $$ +BEGIN + RETURN QUERY + WITH cohort_students AS ( + SELECT + nuc.nss_user_id, + c.name AS cohort_name, + c.start_date, + c.end_date + FROM "LearningAPI_nssusercohort" nuc + JOIN "LearningAPI_cohort" c ON nuc.cohort_id = c.id + WHERE nuc.cohort_id = student_cohort_id + ), + student_info AS ( + SELECT + au.id, + (au.first_name || ' ' || au.last_name)::TEXT AS full_name, + cs.cohort_name::TEXT, + cs.start_date::DATE, + cs.end_date::DATE + FROM auth_user au + JOIN cohort_students cs ON au.id = cs.nss_user_id + ), + latest_project AS ( + SELECT + sp.student_id, + p.id AS project_id, + p.index AS project_index, + p.name AS project_name, + b.id AS book_id, + b.index AS book_index, + b.name AS book_name, + sp.date_created + FROM "LearningAPI_studentproject" sp + JOIN "LearningAPI_project" p ON sp.project_id = p.id + JOIN "LearningAPI_book" b ON p.book_id = b.id + WHERE sp.student_id IN (SELECT nss_user_id FROM cohort_students) + ORDER BY sp.date_created DESC + LIMIT 1 + ), + assessment_status_agg AS ( + SELECT + DISTINCT ON (sa.student_id) sa.student_id, + sa.assessment_id, + sa.status_id, + CASE + WHEN sa.status_id = 1 THEN 'In Progress' + WHEN sa.status_id = 2 THEN 'Ready for Review' + WHEN sa.status_id = 3 THEN 'Reviewed and Incomplete' + WHEN sa.status_id = 4 THEN 'Reviewed and Complete' + ELSE 'Unknown' + END AS status + FROM "LearningAPI_studentassessment" sa + JOIN "LearningAPI_assessment" a ON sa.assessment_id = a.id + JOIN latest_project lp + ON sa.student_id = lp.student_id + AND a.book_id = lp.book_id + WHERE sa.student_id IN (SELECT nss_user_id FROM cohort_students) + ORDER BY sa.student_id, sa.date_created DESC + ), + score_calc AS ( + SELECT + lr.student_id, + SUM(lw.weight) AS total_score + FROM "LearningAPI_learningrecord" lr + JOIN "LearningAPI_learningweight" lw ON lr.weight_id = lw.id + WHERE lr.student_id IN (SELECT nss_user_id FROM cohort_students) AND lr.achieved = TRUE + GROUP BY lr.student_id + ) + SELECT + si.full_name, + lp.project_id::INT, + lp.project_index::INT, + lp.project_name::TEXT, + lp.book_id::INT, + lp.book_index::INT, + lp.book_name::TEXT, + si.cohort_name::TEXT AS current_cohort_name, + si.start_date::DATE AS current_cohort_start_date, + si.end_date::DATE AS current_cohort_end_date, + coalesce(asa.status_id, 0)::INT AS assessment_status_id, + coalesce(asa.status, 'Not Available')::TEXT AS assessment_status, + coalesce(sc.total_score, 0)::INT AS total_score + FROM student_info si + LEFT JOIN latest_project lp ON si.id = lp.student_id + LEFT JOIN assessment_status_agg asa ON si.id = asa.student_id + LEFT JOIN score_calc sc ON si.id = sc.student_id; +END; $$ +LANGUAGE plpgsql; + diff --git a/LearningAPI/views/course_view.py b/LearningAPI/views/course_view.py index be7188a..42fa8ba 100644 --- a/LearningAPI/views/course_view.py +++ b/LearningAPI/views/course_view.py @@ -116,7 +116,16 @@ def stats(self, request, pk): from django.db import connection with connection.cursor() as cursor: - cursor.execute("SELECT * FROM get_project_average_start_delay(%s)", [pk]) + cursor.execute(""" + SELECT + BookName, + BookIndex, + ProjectName, + ProjectIndex, + AverageStartDelay + FROM + get_project_average_start_delay(%s) + """, [pk]) columns = [col[0] for col in cursor.description] results = [ dict(zip(columns, row)) From 3eda07b7662081232ba47ad04e9f10c834a190f4 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Sun, 11 Feb 2024 13:40:22 -0600 Subject: [PATCH 02/11] Postgres function --- LearningAPI.session.sql | 285 ++++------------------------------------ 1 file changed, 23 insertions(+), 262 deletions(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 2a47337..92e052e 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -283,166 +283,39 @@ ORDER BY book.index, -DROP FUNCTION IF EXISTS get_student_details(INT); +DROP FUNCTION IF EXISTS get_cohort_student_data(INT); +select * from get_cohort_student_data(11); -select * from get_student_details(207); -- No assessment -select * from get_student_details(176); -- In progress -select * from get_student_details(205); -- Completed assessment - - - -CREATE OR REPLACE FUNCTION get_student_details(student_user_id INT) +CREATE FUNCTION get_cohort_student_data(selected_cohort_id INT) RETURNS TABLE ( - full_name TEXT, + user_id INT, + github_handle TEXT, + name TEXT, + assessment_status_id INT, project_id INT, project_index INT, - latest_project_name TEXT, + project_name TEXT, book_id INT, book_index INT, - latest_book_name TEXT, - current_cohort_name TEXT, - current_cohort_start_date DATE, - current_cohort_end_date DATE, - assessment_status_id INT, - assessment_status TEXT, - total_score INT + book_name TEXT, + score INT ) AS $$ BEGIN RETURN QUERY - WITH student_info AS ( - SELECT - au.id, - au.first_name || ' ' || au.last_name AS full_name - FROM auth_user au - WHERE au.id = student_user_id - ), - latest_project AS ( - SELECT - sp.student_id, - p.id AS project_id, - p.index AS project_index, - p.name AS project_name, - b.id AS book_id, - b.index AS book_index, - b.name AS book_name, - sp.date_created - FROM "LearningAPI_studentproject" sp - JOIN "LearningAPI_project" p ON sp.project_id = p.id - JOIN "LearningAPI_book" b ON p.book_id = b.id - WHERE sp.student_id = student_user_id - ORDER BY sp.date_created DESC - LIMIT 1 - ), - current_cohort AS ( - SELECT - nuc.nss_user_id, - c.name AS cohort_name, - c.start_date, - c.end_date - FROM "LearningAPI_nssusercohort" nuc - JOIN "LearningAPI_cohort" c ON nuc.cohort_id = c.id - WHERE nuc.nss_user_id = student_user_id - ORDER BY nuc.id DESC - LIMIT 1 - ), - assessment_status_agg AS ( - SELECT - sa.student_id, - sa.assessment_id, - sa.status_id, - CASE - WHEN sa.status_id = 1 THEN 'In Progress' - WHEN sa.status_id = 2 THEN 'Ready for Review' - WHEN sa.status_id = 3 THEN 'Reviewed and Incomplete' - WHEN sa.status_id = 4 THEN 'Reviewed and Complete' - ELSE 'Unknown' - END AS status - FROM "LearningAPI_studentassessment" sa - JOIN latest_project lp ON sa.student_id = lp.student_id - JOIN "LearningAPI_assessment" a ON sa.assessment_id = a.id AND a.book_id = lp.book_id - WHERE sa.student_id = student_user_id - ORDER BY sa.date_created DESC - LIMIT 1 - ), - score_calc AS ( - SELECT - lr.student_id, - SUM(lw.weight) AS total_score - FROM "LearningAPI_learningrecord" lr - JOIN "LearningAPI_learningweight" lw ON lr.weight_id = lw.id - WHERE lr.student_id = student_user_id AND lr.achieved = TRUE - GROUP BY lr.student_id - ) - SELECT - si.full_name::text, - lp.project_id::int AS project_id, - lp.project_index::int AS project_index, - lp.project_name::text AS latest_project_name, - lp.book_id::int AS book_id, - lp.book_index::int AS book_index, - lp.book_name::text AS latest_book_name, - cc.cohort_name::text AS current_cohort_name, - cc.start_date::date AS current_cohort_start_date, - cc.end_date::date AS current_cohort_end_date, - coalesce(asa.status_id::int, 0)::int AS assessment_status_id, - coalesce(asa.status::text, 'Not Available')::text AS assessment_status, - coalesce(sc.total_score::int, 0)::int AS total_score - FROM student_info si - LEFT JOIN latest_project lp ON si.id = lp.student_id - LEFT JOIN current_cohort cc ON si.id = cc.nss_user_id - LEFT JOIN assessment_status_agg asa ON si.id = asa.student_id - LEFT JOIN score_calc sc ON si.id = sc.student_id; -END; $$ -LANGUAGE plpgsql; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -select * from get_student_details(207); -- No assessment -select * from get_student_details(176); -- In progress -select * from get_student_details(205); -- Completed assessment - - - - SELECT - nu.user_id, - nu.github_handle, + nu.user_id::int, + nu.github_handle::text, au."first_name" || ' ' || au."last_name" AS name, - sa.status_id AS assessment_status_id, - sp."project_id" AS project_id, - p.index AS project_index, - p."name" AS project_name, - b.id AS book_id, - b.index AS book_index, - b.name AS book_name, - lr.total_score AS score + sa.status_id::int AS assessment_status_id, + sp.project_id::int AS project_id, + p.index::int AS project_index, + p.name::text AS project_name, + b.id::int AS book_id, + b.index::int AS book_index, + b.name::text AS book_name, + lr.total_score::int AS score FROM "LearningAPI_nssuser" nu JOIN "auth_user" au ON au."id" = nu."user_id" JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" @@ -474,122 +347,10 @@ SELECT WHERE lr."achieved" = true GROUP BY lr."student_id" ) lr ON lr."student_id" = nu."id" - WHERE nc."cohort_id" = 11 + WHERE nc."cohort_id" = selected_cohort_id ORDER BY b.index ASC, p.index ASC; +END; +$$ LANGUAGE plpgsql; - - - -DROP FUNCTION IF EXISTS get_cohort_student_details(INT); - -select * from get_cohort_student_details(11); -- No assessment - - - -CREATE OR REPLACE FUNCTION get_cohort_student_details(student_cohort_id INT) -RETURNS TABLE ( - full_name TEXT, - project_id INT, - project_index INT, - latest_project_name TEXT, - book_id INT, - book_index INT, - latest_book_name TEXT, - current_cohort_name TEXT, - current_cohort_start_date DATE, - current_cohort_end_date DATE, - assessment_status_id INT, - assessment_status TEXT, - total_score INT -) AS $$ -BEGIN - RETURN QUERY - WITH cohort_students AS ( - SELECT - nuc.nss_user_id, - c.name AS cohort_name, - c.start_date, - c.end_date - FROM "LearningAPI_nssusercohort" nuc - JOIN "LearningAPI_cohort" c ON nuc.cohort_id = c.id - WHERE nuc.cohort_id = student_cohort_id - ), - student_info AS ( - SELECT - au.id, - (au.first_name || ' ' || au.last_name)::TEXT AS full_name, - cs.cohort_name::TEXT, - cs.start_date::DATE, - cs.end_date::DATE - FROM auth_user au - JOIN cohort_students cs ON au.id = cs.nss_user_id - ), - latest_project AS ( - SELECT - sp.student_id, - p.id AS project_id, - p.index AS project_index, - p.name AS project_name, - b.id AS book_id, - b.index AS book_index, - b.name AS book_name, - sp.date_created - FROM "LearningAPI_studentproject" sp - JOIN "LearningAPI_project" p ON sp.project_id = p.id - JOIN "LearningAPI_book" b ON p.book_id = b.id - WHERE sp.student_id IN (SELECT nss_user_id FROM cohort_students) - ORDER BY sp.date_created DESC - LIMIT 1 - ), - assessment_status_agg AS ( - SELECT - DISTINCT ON (sa.student_id) sa.student_id, - sa.assessment_id, - sa.status_id, - CASE - WHEN sa.status_id = 1 THEN 'In Progress' - WHEN sa.status_id = 2 THEN 'Ready for Review' - WHEN sa.status_id = 3 THEN 'Reviewed and Incomplete' - WHEN sa.status_id = 4 THEN 'Reviewed and Complete' - ELSE 'Unknown' - END AS status - FROM "LearningAPI_studentassessment" sa - JOIN "LearningAPI_assessment" a ON sa.assessment_id = a.id - JOIN latest_project lp - ON sa.student_id = lp.student_id - AND a.book_id = lp.book_id - WHERE sa.student_id IN (SELECT nss_user_id FROM cohort_students) - ORDER BY sa.student_id, sa.date_created DESC - ), - score_calc AS ( - SELECT - lr.student_id, - SUM(lw.weight) AS total_score - FROM "LearningAPI_learningrecord" lr - JOIN "LearningAPI_learningweight" lw ON lr.weight_id = lw.id - WHERE lr.student_id IN (SELECT nss_user_id FROM cohort_students) AND lr.achieved = TRUE - GROUP BY lr.student_id - ) - SELECT - si.full_name, - lp.project_id::INT, - lp.project_index::INT, - lp.project_name::TEXT, - lp.book_id::INT, - lp.book_index::INT, - lp.book_name::TEXT, - si.cohort_name::TEXT AS current_cohort_name, - si.start_date::DATE AS current_cohort_start_date, - si.end_date::DATE AS current_cohort_end_date, - coalesce(asa.status_id, 0)::INT AS assessment_status_id, - coalesce(asa.status, 'Not Available')::TEXT AS assessment_status, - coalesce(sc.total_score, 0)::INT AS total_score - FROM student_info si - LEFT JOIN latest_project lp ON si.id = lp.student_id - LEFT JOIN assessment_status_agg asa ON si.id = asa.student_id - LEFT JOIN score_calc sc ON si.id = sc.student_id; -END; $$ -LANGUAGE plpgsql; - From 993631de6264a0346286414678134e87110e1998 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Thu, 15 Feb 2024 17:15:41 -0600 Subject: [PATCH 03/11] Now gathering notes with the sql function --- LearningAPI.session.sql | 95 +++++++++++++++++++++++---- LearningAPI/views/student_view.py | 104 ++++++++++++++++++++++++------ 2 files changed, 167 insertions(+), 32 deletions(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 92e052e..843591b 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -300,26 +300,31 @@ RETURNS TABLE ( book_id INT, book_index INT, book_name TEXT, - score INT + score INT, + student_notes TEXT ) AS $$ BEGIN RETURN QUERY + SELECT nu.user_id::int, nu.github_handle::text, - au."first_name" || ' ' || au."last_name" AS name, - sa.status_id::int AS assessment_status_id, - sp.project_id::int AS project_id, - p.index::int AS project_index, - p.name::text AS project_name, - b.id::int AS book_id, - b.index::int AS book_index, - b.name::text AS book_name, - lr.total_score::int AS score + au."first_name" || ' ' || au."last_name" AS student_name, + COALESCE(sa.status_id::int, 0) AS assessment_status_id, + sp.project_id::int AS current_project_id, + p.index::int AS current_project_index, + p.name::text AS current_project_name, + b.id::int AS current_book_id, + b.index::int AS current_book_index, + b.name::text AS current_book_name, + lr.total_score::int AS score, + COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on)))::text AS student_notes FROM "LearningAPI_nssuser" nu JOIN "auth_user" au ON au."id" = nu."user_id" JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" + LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" + LEFT JOIN "LearningAPI_studentproject" sp ON sp."student_id" = nu."id" AND sp."date_created" = ( @@ -347,10 +352,78 @@ SELECT WHERE lr."achieved" = true GROUP BY lr."student_id" ) lr ON lr."student_id" = nu."id" - WHERE nc."cohort_id" = selected_cohort_id + WHERE nc."cohort_id" = 11 + AND au.is_active = TRUE + AND au.is_staff = FALSE + GROUP BY nu.user_id, nu.github_handle, + student_name, assessment_status_id, current_project_id, + current_project_index, current_project_name, current_book_id, + current_book_index, current_book_name, score ORDER BY b.index ASC, p.index ASC; END; $$ LANGUAGE plpgsql; + + + + + + +SELECT + nu.user_id::int, + nu.github_handle::text, + au."first_name" || ' ' || au."last_name" AS student_name, + COALESCE(sa.status_id::int, 0) AS assessment_status_id, + sp.project_id::int AS current_project_id, + p.index::int AS current_project_index, + p.name::text AS current_project_name, + b.id::int AS current_book_id, + b.index::int AS current_book_index, + b.name::text AS current_book_name, + lr.total_score::int AS score, + COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on))) AS student_notes + FROM "LearningAPI_nssuser" nu + JOIN "auth_user" au ON au."id" = nu."user_id" + JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" + JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" + LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" + + LEFT JOIN "LearningAPI_studentproject" sp + ON sp."student_id" = nu."id" + AND sp."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentproject" + WHERE "student_id" = nu."id" + ) + LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" + LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" + LEFT JOIN "LearningAPI_assessment" la + ON b.id = la.book_id + LEFT JOIN "LearningAPI_studentassessment" sa + ON sa."student_id" = nu."id" + AND sa."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentassessment" + WHERE "student_id" = nu."id" + ) + AND sa.assessment_id = la.id + LEFT JOIN ( + SELECT lr."student_id", SUM(lw."weight") AS total_score + FROM "LearningAPI_learningrecord" lr + JOIN "LearningAPI_learningrecordentry" lre ON lre."record_id" = lr."id" + JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" + WHERE lr."achieved" = true + GROUP BY lr."student_id" + ) lr ON lr."student_id" = nu."id" + WHERE nc."cohort_id" = 11 + AND au.is_active = TRUE + AND au.is_staff = FALSE + GROUP BY user_id, nu.github_handle, + student_name, assessment_status_id, current_project_id, + current_project_index, current_project_name, current_book_id, + current_book_index, current_book_name, score + ORDER BY b.index ASC, + p.index ASC + ; diff --git a/LearningAPI/views/student_view.py b/LearningAPI/views/student_view.py index fab44e3..8433024 100644 --- a/LearningAPI/views/student_view.py +++ b/LearningAPI/views/student_view.py @@ -1,9 +1,9 @@ """Student view module""" import os +import json import logging - import requests -from django.db.models import Q +from django.db import connection from django.http import HttpResponseServerError from django.utils.decorators import method_decorator from rest_framework import serializers, status @@ -14,7 +14,7 @@ from LearningAPI.decorators import is_instructor from LearningAPI.models import Tag -from LearningAPI.models.coursework import StudentProject, Project +from LearningAPI.models.coursework import StudentProject, Project, Capstone from LearningAPI.models.people import (StudentNote, NssUser, StudentAssessment, OneOnOneNote, StudentPersonality, Assessment, StudentAssessmentStatus, StudentTag) @@ -123,29 +123,91 @@ def list(self, request): Returns: Response -- JSON serialized array """ - cohort = self.request.query_params.get('cohort', None) - search_terms = self.request.query_params.get('q', None) - students = NssUser.objects.filter(user__is_active=True, user__is_staff=False) - serializer = SingleStudent(students, many=True) + class CapstoneSerializer(serializers.ModelSerializer): + """JSON serializer""" + class Meta: + model = Capstone + fields = ( 'id', 'course', 'proposal_url', ) + depth = 1 + + + class QuickStudent(serializers.Serializer): + """JSON serializer""" + # notes = serializers.SerializerMethodField() + proposals = serializers.SerializerMethodField() + + id = serializers.IntegerField() + github_handle = serializers.CharField(max_length=100) + name = serializers.CharField(max_length=100) + assessment_status_id = serializers.IntegerField() + project_id = serializers.IntegerField() + project_index = serializers.IntegerField() + project_name = serializers.CharField(max_length=100) + book_id = serializers.IntegerField() + book_index = serializers.IntegerField() + book_name = serializers.CharField(max_length=100) + score = serializers.IntegerField() + notes = serializers.ListField() + + def get_proposals(self, obj): + return [] + records = Capstone.objects.filter(student__user__id=obj['id']).order_by("pk") + return CapstoneSerializer(records, many=True).data + + + - if search_terms is not None: - for letter in list(search_terms): - students = students.filter( - Q(user__first_name__icontains=letter) - | Q(user__last_name__icontains=letter) - ) - serializer = SingleStudent(students, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) - if cohort is not None: - students = students.filter(assigned_cohorts__cohort__id=cohort) - serializer = MicroStudents(students, many=True) - page = self.paginate_queryset(serializer.data) - paginated_response = self.get_paginated_response(page) - return paginated_response + + + + cohort = self.request.query_params.get('cohort', None) + + if cohort is None: + return Response({ + 'message': 'Student lists can only be requested by cohort' + }, status=status.HTTP_400_BAD_REQUEST) + + else: + with connection.cursor() as cursor: + cursor.execute(""" + SELECT + user_id AS id, + github_handle, + name, + assessment_status_id, + project_id, + project_index, + project_name, + book_id, + book_index, + book_name, + score, + student_notes + FROM + get_cohort_student_data(%s) + """, [cohort]) + columns = [col[0] for col in cursor.description] + results = cursor.fetchall() + + students = [] + for row in results: + student = dict(zip(columns, row)) + student['proposals'] = [] + student['project_duration'] = 0 + student['notes'] = json.loads(student['student_notes']) + students.append(student) + + serializer = QuickStudent(data=students, many=True) + if serializer.is_valid(): + return Response(serializer.data, status=status.HTTP_200_OK) + else: + return Response({'message': 'Error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + @method_decorator(is_instructor()) @action(methods=['post', 'put'], detail=True) From cdd43e30f9f81151085bb1c95f0fb88b28e34893 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Thu, 15 Feb 2024 19:00:44 -0600 Subject: [PATCH 04/11] Cohort info and Github avatar --- LearningAPI.session.sql | 231 ++++++++++++++++-------------- LearningAPI/views/student_view.py | 19 ++- 2 files changed, 136 insertions(+), 114 deletions(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 843591b..76b77f9 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -292,7 +292,10 @@ CREATE FUNCTION get_cohort_student_data(selected_cohort_id INT) RETURNS TABLE ( user_id INT, github_handle TEXT, - name TEXT, + extra_data TEXT, + student_name TEXT, + current_cohort TEXT, + current_cohort_id INT, assessment_status_id INT, project_id INT, project_index INT, @@ -305,62 +308,66 @@ RETURNS TABLE ( ) AS $$ BEGIN RETURN QUERY - SELECT - nu.user_id::int, - nu.github_handle::text, - au."first_name" || ' ' || au."last_name" AS student_name, - COALESCE(sa.status_id::int, 0) AS assessment_status_id, - sp.project_id::int AS current_project_id, - p.index::int AS current_project_index, - p.name::text AS current_project_name, - b.id::int AS current_book_id, - b.index::int AS current_book_index, - b.name::text AS current_book_name, - lr.total_score::int AS score, - COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on)))::text AS student_notes - FROM "LearningAPI_nssuser" nu - JOIN "auth_user" au ON au."id" = nu."user_id" - JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" - JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" - LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" - - LEFT JOIN "LearningAPI_studentproject" sp - ON sp."student_id" = nu."id" - AND sp."date_created" = ( - SELECT MAX("date_created") - FROM "LearningAPI_studentproject" - WHERE "student_id" = nu."id" - ) - LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" - LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" - LEFT JOIN "LearningAPI_assessment" la - ON b.id = la.book_id - LEFT JOIN "LearningAPI_studentassessment" sa - ON sa."student_id" = nu."id" - AND sa."date_created" = ( - SELECT MAX("date_created") - FROM "LearningAPI_studentassessment" - WHERE "student_id" = nu."id" - ) - AND sa.assessment_id = la.id - LEFT JOIN ( - SELECT lr."student_id", SUM(lw."weight") AS total_score - FROM "LearningAPI_learningrecord" lr - JOIN "LearningAPI_learningrecordentry" lre ON lre."record_id" = lr."id" - JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" - WHERE lr."achieved" = true - GROUP BY lr."student_id" - ) lr ON lr."student_id" = nu."id" - WHERE nc."cohort_id" = 11 - AND au.is_active = TRUE - AND au.is_staff = FALSE - GROUP BY nu.user_id, nu.github_handle, - student_name, assessment_status_id, current_project_id, - current_project_index, current_project_name, current_book_id, - current_book_index, current_book_name, score - ORDER BY b.index ASC, - p.index ASC; + nu.user_id::int, + nu.github_handle::text, + social.extra_data::text, + au."first_name" || ' ' || au."last_name" AS student_name, + c.name::text AS current_cohort, + c.id::int AS current_cohort_id, + COALESCE(sa.status_id::int, 0) AS assessment_status_id, + sp.project_id::int AS current_project_id, + p.index::int AS current_project_index, + p.name::text AS current_project_name, + b.id::int AS current_book_id, + b.index::int AS current_book_index, + b.name::text AS current_book_name, + lr.total_score::int AS score, + COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on)))::text AS student_notes +FROM "LearningAPI_nssuser" nu +JOIN "auth_user" au ON au."id" = nu."user_id" +JOIN "socialaccount_socialaccount" social ON social.user_id = nu.id +JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" +JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" +LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" + +LEFT JOIN "LearningAPI_studentproject" sp + ON sp."student_id" = nu."id" + AND sp."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentproject" + WHERE "student_id" = nu."id" + ) +LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" +LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" +LEFT JOIN "LearningAPI_assessment" la + ON b.id = la.book_id +LEFT JOIN "LearningAPI_studentassessment" sa + ON sa."student_id" = nu."id" + AND sa."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentassessment" + WHERE "student_id" = nu."id" + ) + AND sa.assessment_id = la.id +LEFT JOIN ( + SELECT lr."student_id", SUM(lw."weight") AS total_score + FROM "LearningAPI_learningrecord" lr + JOIN "LearningAPI_learningrecordentry" lre ON lre."record_id" = lr."id" + JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" + WHERE lr."achieved" = true + GROUP BY lr."student_id" +) lr ON lr."student_id" = nu."id" +WHERE nc."cohort_id" = 11 +AND au.is_active = TRUE +AND au.is_staff = FALSE +GROUP BY nu.user_id, nu.github_handle, social.extra_data, + student_name, current_cohort, current_cohort_id, assessment_status_id, + current_project_id, current_project_index, current_project_name, + current_book_id, current_book_index, current_book_name, score +ORDER BY b.index ASC, + p.index ASC; + END; $$ LANGUAGE plpgsql; @@ -372,58 +379,60 @@ $$ LANGUAGE plpgsql; SELECT - nu.user_id::int, - nu.github_handle::text, - au."first_name" || ' ' || au."last_name" AS student_name, - COALESCE(sa.status_id::int, 0) AS assessment_status_id, - sp.project_id::int AS current_project_id, - p.index::int AS current_project_index, - p.name::text AS current_project_name, - b.id::int AS current_book_id, - b.index::int AS current_book_index, - b.name::text AS current_book_name, - lr.total_score::int AS score, - COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on))) AS student_notes - FROM "LearningAPI_nssuser" nu - JOIN "auth_user" au ON au."id" = nu."user_id" - JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" - JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" - LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" - - LEFT JOIN "LearningAPI_studentproject" sp - ON sp."student_id" = nu."id" - AND sp."date_created" = ( - SELECT MAX("date_created") - FROM "LearningAPI_studentproject" - WHERE "student_id" = nu."id" - ) - LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" - LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" - LEFT JOIN "LearningAPI_assessment" la - ON b.id = la.book_id - LEFT JOIN "LearningAPI_studentassessment" sa - ON sa."student_id" = nu."id" - AND sa."date_created" = ( - SELECT MAX("date_created") - FROM "LearningAPI_studentassessment" - WHERE "student_id" = nu."id" - ) - AND sa.assessment_id = la.id - LEFT JOIN ( - SELECT lr."student_id", SUM(lw."weight") AS total_score - FROM "LearningAPI_learningrecord" lr - JOIN "LearningAPI_learningrecordentry" lre ON lre."record_id" = lr."id" - JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" - WHERE lr."achieved" = true - GROUP BY lr."student_id" - ) lr ON lr."student_id" = nu."id" - WHERE nc."cohort_id" = 11 - AND au.is_active = TRUE - AND au.is_staff = FALSE - GROUP BY user_id, nu.github_handle, - student_name, assessment_status_id, current_project_id, - current_project_index, current_project_name, current_book_id, - current_book_index, current_book_name, score - ORDER BY b.index ASC, - p.index ASC - ; + nu.user_id::int, + nu.github_handle::text, + social.extra_data::text, + au."first_name" || ' ' || au."last_name" AS student_name, + c.name::text AS current_cohort, + COALESCE(sa.status_id::int, 0) AS assessment_status_id, + sp.project_id::int AS current_project_id, + p.index::int AS current_project_index, + p.name::text AS current_project_name, + b.id::int AS current_book_id, + b.index::int AS current_book_index, + b.name::text AS current_book_name, + lr.total_score::int AS score, + COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on)))::text AS student_notes +FROM "LearningAPI_nssuser" nu +JOIN "auth_user" au ON au."id" = nu."user_id" +JOIN "socialaccount_socialaccount" social ON social.user_id = nu.id +JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" +JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" +LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" + +LEFT JOIN "LearningAPI_studentproject" sp + ON sp."student_id" = nu."id" + AND sp."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentproject" + WHERE "student_id" = nu."id" + ) +LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" +LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" +LEFT JOIN "LearningAPI_assessment" la + ON b.id = la.book_id +LEFT JOIN "LearningAPI_studentassessment" sa + ON sa."student_id" = nu."id" + AND sa."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentassessment" + WHERE "student_id" = nu."id" + ) + AND sa.assessment_id = la.id +LEFT JOIN ( + SELECT lr."student_id", SUM(lw."weight") AS total_score + FROM "LearningAPI_learningrecord" lr + JOIN "LearningAPI_learningrecordentry" lre ON lre."record_id" = lr."id" + JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" + WHERE lr."achieved" = true + GROUP BY lr."student_id" +) lr ON lr."student_id" = nu."id" +WHERE nc."cohort_id" = 11 +AND au.is_active = TRUE +AND au.is_staff = FALSE +GROUP BY nu.user_id, nu.github_handle, social.extra_data, + student_name, current_cohort, assessment_status_id, current_project_id, + current_project_index, current_project_name, current_book_id, + current_book_index, current_book_name, score +ORDER BY b.index ASC, + p.index ASC; diff --git a/LearningAPI/views/student_view.py b/LearningAPI/views/student_view.py index 8433024..60bc665 100644 --- a/LearningAPI/views/student_view.py +++ b/LearningAPI/views/student_view.py @@ -134,12 +134,13 @@ class Meta: class QuickStudent(serializers.Serializer): """JSON serializer""" - # notes = serializers.SerializerMethodField() proposals = serializers.SerializerMethodField() id = serializers.IntegerField() github_handle = serializers.CharField(max_length=100) name = serializers.CharField(max_length=100) + current_cohort = serializers.DictField() + avatar = serializers.CharField() assessment_status_id = serializers.IntegerField() project_id = serializers.IntegerField() project_index = serializers.IntegerField() @@ -150,8 +151,12 @@ class QuickStudent(serializers.Serializer): score = serializers.IntegerField() notes = serializers.ListField() + def get_avatar(self, obj): + github = obj.user.socialaccount_set.get(user=obj['id']) + return github.extra_data["avatar_url"] + def get_proposals(self, obj): - return [] + # return [] records = Capstone.objects.filter(student__user__id=obj['id']).order_by("pk") return CapstoneSerializer(records, many=True).data @@ -177,7 +182,10 @@ def get_proposals(self, obj): SELECT user_id AS id, github_handle, - name, + extra_data, + student_name AS name, + current_cohort AS cohort_name, + current_cohort_id AS cohort_id, assessment_status_id, project_id, project_index, @@ -198,6 +206,11 @@ def get_proposals(self, obj): student = dict(zip(columns, row)) student['proposals'] = [] student['project_duration'] = 0 + student['current_cohort'] = { + 'id': student['cohort_id'], + 'name': student['cohort_name'] + } + student['avatar'] = json.loads(student['extra_data'])["avatar_url"] student['notes'] = json.loads(student['student_notes']) students.append(student) From f8751df5103bc4dfd395996bd2c46ca8d4eb3200 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Thu, 15 Feb 2024 22:07:07 -0600 Subject: [PATCH 05/11] Remove duplicate results in query --- LearningAPI.session.sql | 141 ++++++++++++++++++++++++------ LearningAPI/views/student_view.py | 30 +++---- 2 files changed, 124 insertions(+), 47 deletions(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 76b77f9..718a803 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -297,17 +297,19 @@ RETURNS TABLE ( current_cohort TEXT, current_cohort_id INT, assessment_status_id INT, - project_id INT, - project_index INT, - project_name TEXT, - book_id INT, - book_index INT, - book_name TEXT, + current_project_id INT, + current_project_index INT, + current_project_name TEXT, + current_book_id INT, + current_book_index INT, + current_book_name TEXT, score INT, - student_notes TEXT + student_notes TEXT, + capstone_proposals TEXT ) AS $$ BEGIN RETURN QUERY + SELECT nu.user_id::int, nu.github_handle::text, @@ -323,20 +325,54 @@ SELECT b.index::int AS current_book_index, b.name::text AS current_book_name, lr.total_score::int AS score, - COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on)))::text AS student_notes + COALESCE( + json_agg( + json_build_object( + 'note_id', sn.id, + 'note', sn.note, + 'created_on', sn.created_on + ) + ) + )::text AS student_notes, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', c."id", + 'status', ps.status, + 'proposal_url', c."proposal_url", + 'created_on', sct.date + ) + ) + FROM "LearningAPI_capstone" c + JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id + JOIN "LearningAPI_proposalstatus" ps ON ps.id = sct.status_id + WHERE c."student_id" = nu."user_id" + AND sct.id = ( + SELECT sct.id + FROM "LearningAPI_capstone" c + JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id + WHERE c.student_id = nu.user_id + ORDER BY sct.id DESC + LIMIT 1 + ) + ), '[]' + )::text AS capstone_proposals FROM "LearningAPI_nssuser" nu JOIN "auth_user" au ON au."id" = nu."user_id" -JOIN "socialaccount_socialaccount" social ON social.user_id = nu.id -JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" -JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" -LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" - +LEFT JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" +LEFT JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" +JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" +LEFT JOIN "socialaccount_socialaccount" social ON social.user_id = nu.id +LEFT JOIN "LearningAPI_capstone" sc ON sc.student_id = nu."id" LEFT JOIN "LearningAPI_studentproject" sp ON sp."student_id" = nu."id" - AND sp."date_created" = ( - SELECT MAX("date_created") + AND sp.id = ( + SELECT id FROM "LearningAPI_studentproject" WHERE "student_id" = nu."id" + ORDER BY id DESC + LIMIT 1 ) LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" @@ -362,9 +398,9 @@ WHERE nc."cohort_id" = 11 AND au.is_active = TRUE AND au.is_staff = FALSE GROUP BY nu.user_id, nu.github_handle, social.extra_data, - student_name, current_cohort, current_cohort_id, assessment_status_id, - current_project_id, current_project_index, current_project_name, - current_book_id, current_book_index, current_book_name, score + student_name, current_cohort, current_cohort_id, assessment_status_id, current_project_id, + current_project_index, current_project_name, current_book_id, + current_book_index, current_book_name, score ORDER BY b.index ASC, p.index ASC; @@ -378,12 +414,25 @@ $$ LANGUAGE plpgsql; + + + + + + + + + + + + SELECT nu.user_id::int, nu.github_handle::text, social.extra_data::text, au."first_name" || ' ' || au."last_name" AS student_name, c.name::text AS current_cohort, + c.id::int AS current_cohort_id, COALESCE(sa.status_id::int, 0) AS assessment_status_id, sp.project_id::int AS current_project_id, p.index::int AS current_project_index, @@ -392,20 +441,54 @@ SELECT b.index::int AS current_book_index, b.name::text AS current_book_name, lr.total_score::int AS score, - COALESCE(json_agg(json_build_object('note_id', sn.id, 'note', sn.note, 'created_on', sn.created_on)))::text AS student_notes + COALESCE( + json_agg( + json_build_object( + 'note_id', sn.id, + 'note', sn.note, + 'created_on', sn.created_on + ) + ) + )::text AS student_notes, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', c."id", + 'status', ps.status, + 'proposal_url', c."proposal_url", + 'created_on', sct.date + ) + ) + FROM "LearningAPI_capstone" c + JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id + JOIN "LearningAPI_proposalstatus" ps ON ps.id = sct.status_id + WHERE c."student_id" = nu."user_id" + AND sct.id = ( + SELECT sct.id + FROM "LearningAPI_capstone" c + JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id + WHERE c.student_id = nu.user_id + ORDER BY sct.id DESC + LIMIT 1 + ) + ), '[]' + )::text AS capstone_proposals FROM "LearningAPI_nssuser" nu JOIN "auth_user" au ON au."id" = nu."user_id" -JOIN "socialaccount_socialaccount" social ON social.user_id = nu.id -JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" -JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" -LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" - +LEFT JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" +LEFT JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" +JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" +LEFT JOIN "socialaccount_socialaccount" social ON social.user_id = nu.id +LEFT JOIN "LearningAPI_capstone" sc ON sc.student_id = nu."id" LEFT JOIN "LearningAPI_studentproject" sp ON sp."student_id" = nu."id" - AND sp."date_created" = ( - SELECT MAX("date_created") + AND sp.id = ( + SELECT id FROM "LearningAPI_studentproject" WHERE "student_id" = nu."id" + ORDER BY id DESC + LIMIT 1 ) LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" @@ -431,8 +514,12 @@ WHERE nc."cohort_id" = 11 AND au.is_active = TRUE AND au.is_staff = FALSE GROUP BY nu.user_id, nu.github_handle, social.extra_data, - student_name, current_cohort, assessment_status_id, current_project_id, + student_name, current_cohort, current_cohort_id, assessment_status_id, current_project_id, current_project_index, current_project_name, current_book_id, current_book_index, current_book_name, score ORDER BY b.index ASC, p.index ASC; + + + + diff --git a/LearningAPI/views/student_view.py b/LearningAPI/views/student_view.py index 60bc665..6077aa0 100644 --- a/LearningAPI/views/student_view.py +++ b/LearningAPI/views/student_view.py @@ -134,8 +134,6 @@ class Meta: class QuickStudent(serializers.Serializer): """JSON serializer""" - proposals = serializers.SerializerMethodField() - id = serializers.IntegerField() github_handle = serializers.CharField(max_length=100) name = serializers.CharField(max_length=100) @@ -150,21 +148,12 @@ class QuickStudent(serializers.Serializer): book_name = serializers.CharField(max_length=100) score = serializers.IntegerField() notes = serializers.ListField() + proposals = serializers.ListField() def get_avatar(self, obj): github = obj.user.socialaccount_set.get(user=obj['id']) return github.extra_data["avatar_url"] - def get_proposals(self, obj): - # return [] - records = Capstone.objects.filter(student__user__id=obj['id']).order_by("pk") - return CapstoneSerializer(records, many=True).data - - - - - - @@ -187,14 +176,15 @@ def get_proposals(self, obj): current_cohort AS cohort_name, current_cohort_id AS cohort_id, assessment_status_id, - project_id, - project_index, - project_name, - book_id, - book_index, - book_name, + current_project_id AS project_id, + current_project_index AS project_index, + current_project_name AS project_name, + current_book_id AS book_id, + current_book_index AS book_index, + current_book_name AS book_name, score, - student_notes + student_notes, + capstone_proposals FROM get_cohort_student_data(%s) """, [cohort]) @@ -204,7 +194,6 @@ def get_proposals(self, obj): students = [] for row in results: student = dict(zip(columns, row)) - student['proposals'] = [] student['project_duration'] = 0 student['current_cohort'] = { 'id': student['cohort_id'], @@ -212,6 +201,7 @@ def get_proposals(self, obj): } student['avatar'] = json.loads(student['extra_data'])["avatar_url"] student['notes'] = json.loads(student['student_notes']) + student['proposals'] = json.loads(student['capstone_proposals']) students.append(student) serializer = QuickStudent(data=students, many=True) From a92eda9484cf6bf1c6af648d1b5c6218b9114ef1 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Fri, 16 Feb 2024 07:47:28 -0600 Subject: [PATCH 06/11] Updated query to get all capstones even if no status --- LearningAPI.session.sql | 33 ++++++++++++++++++++----------- LearningAPI/views/student_view.py | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 718a803..1441ea8 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -341,10 +341,12 @@ SELECT 'id', c."id", 'status', ps.status, 'proposal_url', c."proposal_url", - 'created_on', sct.date + 'created_on', sct.date, + 'course_name', cr.name ) ) FROM "LearningAPI_capstone" c + JOIN "LearningAPI_course" cr ON c.course_id = cr.id JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id JOIN "LearningAPI_proposalstatus" ps ON ps.id = sct.status_id WHERE c."student_id" = nu."user_id" @@ -457,21 +459,27 @@ SELECT 'id', c."id", 'status', ps.status, 'proposal_url', c."proposal_url", - 'created_on', sct.date + 'created_on', tl.date, + 'course_name', cr.name ) ) FROM "LearningAPI_capstone" c - JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id - JOIN "LearningAPI_proposalstatus" ps ON ps.id = sct.status_id + LEFT JOIN ( + SELECT DISTINCT ON ( + ct.capstone_id, c.course_id + ) * + FROM "LearningAPI_capstonetimeline" ct + JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id + JOIN "LearningAPI_course" cr ON c.course_id = cr.id + ORDER BY + ct.capstone_id, + c.course_id, + date DESC + ) tl ON tl.capstone_id = c.id + LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id + LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id WHERE c."student_id" = nu."user_id" - AND sct.id = ( - SELECT sct.id - FROM "LearningAPI_capstone" c - JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id - WHERE c.student_id = nu.user_id - ORDER BY sct.id DESC - LIMIT 1 - ) + ), '[]' )::text AS capstone_proposals FROM "LearningAPI_nssuser" nu @@ -513,6 +521,7 @@ LEFT JOIN ( WHERE nc."cohort_id" = 11 AND au.is_active = TRUE AND au.is_staff = FALSE +AND nu.id = 205 GROUP BY nu.user_id, nu.github_handle, social.extra_data, student_name, current_cohort, current_cohort_id, assessment_status_id, current_project_id, current_project_index, current_project_name, current_book_id, diff --git a/LearningAPI/views/student_view.py b/LearningAPI/views/student_view.py index 6077aa0..26b349b 100644 --- a/LearningAPI/views/student_view.py +++ b/LearningAPI/views/student_view.py @@ -135,6 +135,7 @@ class Meta: class QuickStudent(serializers.Serializer): """JSON serializer""" id = serializers.IntegerField() + proposals = serializers.ListField() github_handle = serializers.CharField(max_length=100) name = serializers.CharField(max_length=100) current_cohort = serializers.DictField() @@ -148,7 +149,6 @@ class QuickStudent(serializers.Serializer): book_name = serializers.CharField(max_length=100) score = serializers.IntegerField() notes = serializers.ListField() - proposals = serializers.ListField() def get_avatar(self, obj): github = obj.user.socialaccount_set.get(user=obj['id']) From 226fca9c3ba203dd582f7af1b36eb7d553cc15d1 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Fri, 16 Feb 2024 08:37:34 -0600 Subject: [PATCH 07/11] Add new proposal sql to function --- LearningAPI.session.sql | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 1441ea8..0cbcc86 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -309,7 +309,6 @@ RETURNS TABLE ( ) AS $$ BEGIN RETURN QUERY - SELECT nu.user_id::int, nu.github_handle::text, @@ -341,23 +340,27 @@ SELECT 'id', c."id", 'status', ps.status, 'proposal_url', c."proposal_url", - 'created_on', sct.date, + 'created_on', tl.date, 'course_name', cr.name ) ) FROM "LearningAPI_capstone" c - JOIN "LearningAPI_course" cr ON c.course_id = cr.id - JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id - JOIN "LearningAPI_proposalstatus" ps ON ps.id = sct.status_id + LEFT JOIN ( + SELECT DISTINCT ON ( + ct.capstone_id, c.course_id + ) * + FROM "LearningAPI_capstonetimeline" ct + JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id + JOIN "LearningAPI_course" cr ON c.course_id = cr.id + ORDER BY + ct.capstone_id, + c.course_id, + date DESC + ) tl ON tl.capstone_id = c.id + LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id + LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id WHERE c."student_id" = nu."user_id" - AND sct.id = ( - SELECT sct.id - FROM "LearningAPI_capstone" c - JOIN "LearningAPI_capstonetimeline" sct ON sct.capstone_id = c.id - WHERE c.student_id = nu.user_id - ORDER BY sct.id DESC - LIMIT 1 - ) + ), '[]' )::text AS capstone_proposals FROM "LearningAPI_nssuser" nu From 0eef2f7e207ad5378ae00aa4023d91872e91acbe Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Sat, 17 Feb 2024 10:14:34 -0600 Subject: [PATCH 08/11] Switched to date time for better ordering --- LearningAPI.session.sql | 72 +++++++++++++++++-- .../0040_alter_capstonetimeline_date.py | 17 +++++ .../models/coursework/capstone_timeline.py | 2 +- LearningAPI/views/student_view.py | 10 --- 4 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 LearningAPI/migrations/0040_alter_capstonetimeline_date.py diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 0cbcc86..6775d9f 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -351,11 +351,10 @@ SELECT ) * FROM "LearningAPI_capstonetimeline" ct JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id - JOIN "LearningAPI_course" cr ON c.course_id = cr.id ORDER BY - ct.capstone_id, c.course_id, - date DESC + ct.capstone_id, + date desc ) tl ON tl.capstone_id = c.id LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id @@ -461,6 +460,7 @@ SELECT json_build_object( 'id', c."id", 'status', ps.status, + 'current_status_id', ps.id, 'proposal_url', c."proposal_url", 'created_on', tl.date, 'course_name', cr.name @@ -473,11 +473,10 @@ SELECT ) * FROM "LearningAPI_capstonetimeline" ct JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id - JOIN "LearningAPI_course" cr ON c.course_id = cr.id ORDER BY - ct.capstone_id, c.course_id, - date DESC + ct.capstone_id, + date desc ) tl ON tl.capstone_id = c.id LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id @@ -524,7 +523,6 @@ LEFT JOIN ( WHERE nc."cohort_id" = 11 AND au.is_active = TRUE AND au.is_staff = FALSE -AND nu.id = 205 GROUP BY nu.user_id, nu.github_handle, social.extra_data, student_name, current_cohort, current_cohort_id, assessment_status_id, current_project_id, current_project_index, current_project_name, current_book_id, @@ -535,3 +533,63 @@ ORDER BY b.index ASC, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +SELECT c."id", + ps.status, + ps.id, + c."proposal_url", + tl.date, + cr.name +FROM "LearningAPI_capstone" c +LEFT JOIN ( + SELECT DISTINCT ON ( + ct.capstone_id, c.course_id + ) * + FROM "LearningAPI_capstonetimeline" ct + JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id + ORDER BY + c.course_id, + ct.capstone_id, + date desc +) tl ON tl.capstone_id = c.id +LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id +LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id +JOIN "LearningAPI_nssuser" usr ON c.student_id = usr.id +WHERE usr.id = 205 +; diff --git a/LearningAPI/migrations/0040_alter_capstonetimeline_date.py b/LearningAPI/migrations/0040_alter_capstonetimeline_date.py new file mode 100644 index 0000000..aec7e73 --- /dev/null +++ b/LearningAPI/migrations/0040_alter_capstonetimeline_date.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.8 on 2024-02-17 15:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("LearningAPI", "0039_add_project_stats_view"), + ] + + operations = [ + migrations.AlterField( + model_name="capstonetimeline", + name="date", + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/LearningAPI/models/coursework/capstone_timeline.py b/LearningAPI/models/coursework/capstone_timeline.py index a767029..ec2dbcc 100644 --- a/LearningAPI/models/coursework/capstone_timeline.py +++ b/LearningAPI/models/coursework/capstone_timeline.py @@ -5,7 +5,7 @@ class CapstoneTimeline(models.Model): """Model for recording history of capstone proposal""" capstone = models.ForeignKey("Capstone", on_delete=models.DO_NOTHING, related_name="statuses") status = models.ForeignKey("ProposalStatus", on_delete=models.DO_NOTHING) - date = models.DateField(auto_now=True, auto_now_add=False) + date = models.DateTimeField(auto_now=True, auto_now_add=False) @property def student(self): diff --git a/LearningAPI/views/student_view.py b/LearningAPI/views/student_view.py index 26b349b..960cebd 100644 --- a/LearningAPI/views/student_view.py +++ b/LearningAPI/views/student_view.py @@ -124,14 +124,6 @@ def list(self, request): Response -- JSON serialized array """ - class CapstoneSerializer(serializers.ModelSerializer): - """JSON serializer""" - class Meta: - model = Capstone - fields = ( 'id', 'course', 'proposal_url', ) - depth = 1 - - class QuickStudent(serializers.Serializer): """JSON serializer""" id = serializers.IntegerField() @@ -210,8 +202,6 @@ def get_avatar(self, obj): else: return Response({'message': 'Error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - @method_decorator(is_instructor()) @action(methods=['post', 'put'], detail=True) def assess(self, request, pk): From 766a6843160fbe564f8e6f637009b589c17497b3 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Sun, 18 Feb 2024 14:13:55 -0600 Subject: [PATCH 09/11] Updated function with current project --- LearningAPI.session.sql | 93 +++------- .../0041_students_by_cohort_db_function.py | 145 +++++++++++++++ LearningAPI/models/people/nssuser.py | 68 ------- LearningAPI/views/profile.py | 25 ++- LearningAPI/views/student_note_view.py | 2 + LearningAPI/views/student_view.py | 168 ++++++------------ 6 files changed, 241 insertions(+), 260 deletions(-) create mode 100644 LearningAPI/migrations/0041_students_by_cohort_db_function.py diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 6775d9f..a27025e 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -305,7 +305,8 @@ RETURNS TABLE ( current_book_name TEXT, score INT, student_notes TEXT, - capstone_proposals TEXT + capstone_proposals TEXT, + project_duration DOUBLE PRECISION ) AS $$ BEGIN RETURN QUERY @@ -361,7 +362,11 @@ SELECT WHERE c."student_id" = nu."user_id" ), '[]' - )::text AS capstone_proposals + )::text AS capstone_proposals, + EXTRACT(YEAR FROM AGE(NOW(), sp.date_created)) * 365 + + EXTRACT(MONTH FROM AGE(NOW(), sp.date_created)) * 30 + + EXTRACT(DAY FROM AGE(NOW(), sp.date_created))::double precision AS project_duration + FROM "LearningAPI_nssuser" nu JOIN "auth_user" au ON au."id" = nu."user_id" LEFT JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" @@ -398,13 +403,14 @@ LEFT JOIN ( WHERE lr."achieved" = true GROUP BY lr."student_id" ) lr ON lr."student_id" = nu."id" -WHERE nc."cohort_id" = 11 +WHERE nc."cohort_id" = selected_cohort_id AND au.is_active = TRUE AND au.is_staff = FALSE GROUP BY nu.user_id, nu.github_handle, social.extra_data, - student_name, current_cohort, current_cohort_id, assessment_status_id, current_project_id, - current_project_index, current_project_name, current_book_id, - current_book_index, current_book_name, score + student_name, current_cohort, current_cohort_id, assessment_status_id, + current_project_id, current_project_index, current_project_name, + project_duration, current_book_id, current_book_index, current_book_name, + score ORDER BY b.index ASC, p.index ASC; @@ -483,7 +489,12 @@ SELECT WHERE c."student_id" = nu."user_id" ), '[]' - )::text AS capstone_proposals + )::text AS capstone_proposals, + EXTRACT(YEAR FROM AGE(NOW(), sp.date_created)) * 365 + + EXTRACT(MONTH FROM AGE(NOW(), sp.date_created)) * 30 + + EXTRACT(DAY FROM AGE(NOW(), sp.date_created))::double precision AS project_duration + + FROM "LearningAPI_nssuser" nu JOIN "auth_user" au ON au."id" = nu."user_id" LEFT JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" @@ -524,72 +535,10 @@ WHERE nc."cohort_id" = 11 AND au.is_active = TRUE AND au.is_staff = FALSE GROUP BY nu.user_id, nu.github_handle, social.extra_data, - student_name, current_cohort, current_cohort_id, assessment_status_id, current_project_id, - current_project_index, current_project_name, current_book_id, + student_name, current_cohort, current_cohort_id, + assessment_status_id, current_project_id, current_project_index, + current_project_name, project_duration, current_book_id, current_book_index, current_book_name, score ORDER BY b.index ASC, p.index ASC; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SELECT c."id", - ps.status, - ps.id, - c."proposal_url", - tl.date, - cr.name -FROM "LearningAPI_capstone" c -LEFT JOIN ( - SELECT DISTINCT ON ( - ct.capstone_id, c.course_id - ) * - FROM "LearningAPI_capstonetimeline" ct - JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id - ORDER BY - c.course_id, - ct.capstone_id, - date desc -) tl ON tl.capstone_id = c.id -LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id -LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id -JOIN "LearningAPI_nssuser" usr ON c.student_id = usr.id -WHERE usr.id = 205 -; diff --git a/LearningAPI/migrations/0041_students_by_cohort_db_function.py b/LearningAPI/migrations/0041_students_by_cohort_db_function.py new file mode 100644 index 0000000..574d5b4 --- /dev/null +++ b/LearningAPI/migrations/0041_students_by_cohort_db_function.py @@ -0,0 +1,145 @@ +# Generated by Django 4.2.8 on 2024-01-10 18:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("LearningAPI", "0040_alter_capstonetimeline_date"), + ] + + operations = [ + migrations.RunSQL( + """ + CREATE FUNCTION get_cohort_student_data(selected_cohort_id INT) + RETURNS TABLE ( + user_id INT, + github_handle TEXT, + extra_data TEXT, + student_name TEXT, + current_cohort TEXT, + current_cohort_id INT, + assessment_status_id INT, + current_project_id INT, + current_project_index INT, + current_project_name TEXT, + current_book_id INT, + current_book_index INT, + current_book_name TEXT, + score INT, + student_notes TEXT, + capstone_proposals TEXT, + project_duration DOUBLE PRECISION + ) AS $$ + BEGIN + RETURN QUERY + SELECT + nu.user_id::int, + nu.github_handle::text, + social.extra_data::text, + au."first_name" || ' ' || au."last_name" AS student_name, + c.name::text AS current_cohort, + c.id::int AS current_cohort_id, + COALESCE(sa.status_id::int, 0) AS assessment_status_id, + sp.project_id::int AS current_project_id, + p.index::int AS current_project_index, + p.name::text AS current_project_name, + b.id::int AS current_book_id, + b.index::int AS current_book_index, + b.name::text AS current_book_name, + lr.total_score::int AS score, + COALESCE( + json_agg( + json_build_object( + 'note_id', sn.id, + 'note', sn.note, + 'created_on', sn.created_on + ) + ) + )::text AS student_notes, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', c."id", + 'status', ps.status, + 'proposal_url', c."proposal_url", + 'created_on', tl.date, + 'course_name', cr.name + ) + ) + FROM "LearningAPI_capstone" c + LEFT JOIN ( + SELECT DISTINCT ON ( + ct.capstone_id, c.course_id + ) * + FROM "LearningAPI_capstonetimeline" ct + JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id + ORDER BY + c.course_id, + ct.capstone_id, + date desc + ) tl ON tl.capstone_id = c.id + LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id + LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id + WHERE c."student_id" = nu."user_id" + + ), '[]' + )::text AS capstone_proposals, + EXTRACT(YEAR FROM AGE(NOW(), sp.date_created)) * 365 + + EXTRACT(MONTH FROM AGE(NOW(), sp.date_created)) * 30 + + EXTRACT(DAY FROM AGE(NOW(), sp.date_created))::double precision AS project_duration + + FROM "LearningAPI_nssuser" nu + JOIN "auth_user" au ON au."id" = nu."user_id" + LEFT JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" + LEFT JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" + JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" + LEFT JOIN "socialaccount_socialaccount" social ON social.user_id = nu.id + LEFT JOIN "LearningAPI_capstone" sc ON sc.student_id = nu."id" + LEFT JOIN "LearningAPI_studentproject" sp + ON sp."student_id" = nu."id" + AND sp.id = ( + SELECT id + FROM "LearningAPI_studentproject" + WHERE "student_id" = nu."id" + ORDER BY id DESC + LIMIT 1 + ) + LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" + LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" + LEFT JOIN "LearningAPI_assessment" la + ON b.id = la.book_id + LEFT JOIN "LearningAPI_studentassessment" sa + ON sa."student_id" = nu."id" + AND sa."date_created" = ( + SELECT MAX("date_created") + FROM "LearningAPI_studentassessment" + WHERE "student_id" = nu."id" + ) + AND sa.assessment_id = la.id + LEFT JOIN ( + SELECT lr."student_id", SUM(lw."weight") AS total_score + FROM "LearningAPI_learningrecord" lr + JOIN "LearningAPI_learningrecordentry" lre ON lre."record_id" = lr."id" + JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" + WHERE lr."achieved" = true + GROUP BY lr."student_id" + ) lr ON lr."student_id" = nu."id" + WHERE nc."cohort_id" = selected_cohort_id + AND au.is_active = TRUE + AND au.is_staff = FALSE + GROUP BY nu.user_id, nu.github_handle, social.extra_data, + student_name, current_cohort, current_cohort_id, assessment_status_id, + current_project_id, current_project_index, current_project_name, + project_duration, current_book_id, current_book_index, current_book_name, + score + ORDER BY b.index ASC, + p.index ASC; + + END; + $$ LANGUAGE plpgsql; + """, + "DROP FUNCTION IF EXISTS get_cohort_student_data(INT);" + ), + ] diff --git a/LearningAPI/models/people/nssuser.py b/LearningAPI/models/people/nssuser.py index d4eb8a6..39aad6b 100644 --- a/LearningAPI/models/people/nssuser.py +++ b/LearningAPI/models/people/nssuser.py @@ -29,74 +29,6 @@ def __str__(self) -> str: def full_name(self): return f'{self.user.first_name} {self.user.last_name}' - @property - def book(self): - student_project = StudentProject.objects.filter(student=self).last() - assigned_cohort = self.assigned_cohorts.order_by("-id").last() - - if student_project is None: - cohort_course = CohortCourse.objects.get(cohort=assigned_cohort.cohort, index=0) - project = Project.objects.get( - book__course=cohort_course.course, book__index=0, index=0) - - return { - "id": project.book.id, - "name": project.book.name, - "project": project.name, - "index": project.book.index, - "project_duration": 0 - } - - current_project_datestamp = student_project.date_created - project_duration = (datetime.datetime.now().date() - current_project_datestamp).days - - return { - "id": student_project.project.book.id, - "name": student_project.project.book.name, - "index": student_project.project.book.index, - "project": student_project.project.name, - "project_duration": project_duration - } - - @property - def name(self): - return str(self) - - @property - def assessment_status(self): - try: - student_assessment = self.assessments.last() # pylint: disable=E1101 - if student_assessment.assessment.book.id != self.book["id"]: - return 0 - - status = student_assessment.status.status - if status == "In Progress": - return 1 - if status == "Ready for Review": - return 2 - if status == "Reviewed and Incomplete": - return 3 - if status == "Reviewed and Complete": - return 4 - - except Exception as ex: - return 0 - - @property - def proposals(self): - try: - lastest_status = CapstoneTimeline.objects.filter(capstone=OuterRef("pk")).order_by("-pk") - - proposals = self.capstones.annotate( - course_name=F("course__name"), - current_status_id=Subquery(lastest_status.values('status__id')[:1]), - current_status=Subquery(lastest_status.values('status__status')[:1]) - ).values('id', 'current_status', 'course_name', 'proposal_url', 'current_status_id') - - return proposals - except Exception: - return [] - @property def score(self): """Return total learning score""" diff --git a/LearningAPI/views/profile.py b/LearningAPI/views/profile.py index 541a67c..55d1b81 100644 --- a/LearningAPI/views/profile.py +++ b/LearningAPI/views/profile.py @@ -4,8 +4,8 @@ from rest_framework.response import Response from allauth.socialaccount.models import SocialAccount from LearningAPI.models.people import Cohort, NssUserCohort, NssUser +from LearningAPI.models.coursework import StudentProject from LearningAPI.models.people.student_personality import StudentPersonality -from LearningAPI.views.student_view import StudentNoteSerializer class Profile(ViewSet): @@ -105,9 +105,8 @@ class Meta: class ProfileSerializer(serializers.ModelSerializer): """JSON serializer""" - feedback = StudentNoteSerializer(many=True) - personality = PersonalitySerializer(many=False) name = serializers.SerializerMethodField() + project = serializers.SerializerMethodField() email = serializers.SerializerMethodField() github = serializers.SerializerMethodField() repos = serializers.SerializerMethodField() @@ -117,6 +116,21 @@ class ProfileSerializer(serializers.ModelSerializer): def get_staff(self, obj): return obj.user.is_staff + def get_project(self, obj): + project = StudentProject.objects.filter(student=obj).last() + if project is not None: + return { + "id": project.project.id, + "name": project.project.name, + "book_name": project.project.book.name, + } + else: + return { + "id": 0, + "name": "Unassigned" + } + + def get_github(self, obj): github = obj.user.socialaccount_set.get(user=obj.user) return github.extra_data["login"] @@ -144,6 +158,5 @@ def get_capstones(self, obj): class Meta: model = NssUser - fields = ('id', 'name', 'email', 'github', 'staff', 'slack_handle', - 'current_cohort', 'feedback', 'repos', 'personality', - 'assessment_overview', 'capstones',) + fields = ('id', 'name', 'project', 'email', 'github', 'staff', 'slack_handle', + 'current_cohort', 'repos', 'assessment_overview', 'capstones',) diff --git a/LearningAPI/views/student_note_view.py b/LearningAPI/views/student_note_view.py index 3967ba2..689b78f 100644 --- a/LearningAPI/views/student_note_view.py +++ b/LearningAPI/views/student_note_view.py @@ -9,6 +9,8 @@ class StudentNoteViewSet(ModelViewSet): """Student note viewset""" + queryset = StudentNote.objects.all() + def list(self, request): studentId = request.query_params.get('studentId', None) diff --git a/LearningAPI/views/student_view.py b/LearningAPI/views/student_view.py index 960cebd..37e3b4c 100644 --- a/LearningAPI/views/student_view.py +++ b/LearningAPI/views/student_view.py @@ -123,33 +123,6 @@ def list(self, request): Returns: Response -- JSON serialized array """ - - class QuickStudent(serializers.Serializer): - """JSON serializer""" - id = serializers.IntegerField() - proposals = serializers.ListField() - github_handle = serializers.CharField(max_length=100) - name = serializers.CharField(max_length=100) - current_cohort = serializers.DictField() - avatar = serializers.CharField() - assessment_status_id = serializers.IntegerField() - project_id = serializers.IntegerField() - project_index = serializers.IntegerField() - project_name = serializers.CharField(max_length=100) - book_id = serializers.IntegerField() - book_index = serializers.IntegerField() - book_name = serializers.CharField(max_length=100) - score = serializers.IntegerField() - notes = serializers.ListField() - - def get_avatar(self, obj): - github = obj.user.socialaccount_set.get(user=obj['id']) - return github.extra_data["avatar_url"] - - - - - cohort = self.request.query_params.get('cohort', None) if cohort is None: @@ -176,7 +149,8 @@ def get_avatar(self, obj): current_book_name AS book_name, score, student_notes, - capstone_proposals + capstone_proposals, + project_duration FROM get_cohort_student_data(%s) """, [cohort]) @@ -186,7 +160,6 @@ def get_avatar(self, obj): students = [] for row in results: student = dict(zip(columns, row)) - student['project_duration'] = 0 student['current_cohort'] = { 'id': student['cohort_id'], 'name': student['cohort_name'] @@ -196,7 +169,7 @@ def get_avatar(self, obj): student['proposals'] = json.loads(student['capstone_proposals']) students.append(student) - serializer = QuickStudent(data=students, many=True) + serializer = CohortStudentSerializer(data=students, many=True) if serializer.is_valid(): return Response(serializer.data, status=status.HTTP_200_OK) else: @@ -400,6 +373,15 @@ class Meta: fields = ['id', 'note', 'created_on', 'author'] +class CoreSkillRecordSerializer(serializers.ModelSerializer): + """Serializer for Core Skill Record""" + + class Meta: + model = CoreSkillRecord + fields = ('id', 'skill', 'level', ) + depth = 1 + + class LearningRecordEntrySerializer(serializers.ModelSerializer): """JSON serializer""" instructor = serializers.SerializerMethodField() @@ -447,6 +429,30 @@ class Meta: ) +class CohortStudentSerializer(serializers.Serializer): + """JSON serializer""" + id = serializers.IntegerField() + github_handle = serializers.CharField(max_length=100) + name = serializers.CharField(max_length=100) + current_cohort = serializers.DictField() + avatar = serializers.CharField() + assessment_status_id = serializers.IntegerField() + project_id = serializers.IntegerField() + project_duration = serializers.IntegerField() + project_index = serializers.IntegerField() + project_name = serializers.CharField(max_length=100) + book_id = serializers.IntegerField() + book_index = serializers.IntegerField() + book_name = serializers.CharField(max_length=100) + score = serializers.IntegerField() + notes = serializers.ListField() + proposals = serializers.ListField() + + def get_avatar(self, obj): + github = obj.user.socialaccount_set.get(user=obj['id']) + return github.extra_data["avatar_url"] + + class StudentSerializer(serializers.ModelSerializer): """JSON serializer""" feedback = StudentNoteSerializer(many=True) @@ -454,8 +460,22 @@ class StudentSerializer(serializers.ModelSerializer): name = serializers.SerializerMethodField() email = serializers.SerializerMethodField() records = serializers.SerializerMethodField() + project = serializers.SerializerMethodField() core_skill_records = serializers.SerializerMethodField() + def get_project(self, obj): + project = StudentProject.objects.filter(student=obj).last() + if project is not None: + return { + "id": project.project.id, + "name": project.project.name + } + else: + return { + "id": 0, + "name": "Unassigned" + } + def get_records(self, obj): records = LearningRecord.objects.filter( student=obj).order_by("achieved") @@ -466,7 +486,7 @@ def get_core_skill_records(self, obj): return CoreSkillRecordSerializer(records, many=True).data def get_name(self, obj): - return f'{obj.user.first_name} {obj.user.last_name}' + return obj.full_name def get_email(self, obj): return obj.user.email @@ -474,87 +494,7 @@ def get_email(self, obj): class Meta: model = NssUser fields = ( - 'id', 'name', 'email', 'github_handle', 'score', 'core_skill_records', - 'feedback', 'records', 'notes', 'capstones', 'current_cohort' + 'id', 'name', 'project', 'email', 'github_handle', 'score', + 'core_skill_records', 'feedback', 'records', 'notes', 'capstones', + 'current_cohort' ) - - -class StudentTagSerializer(serializers.ModelSerializer): - """JSON serializer""" - class Meta: - model = StudentTag - fields = ('id', 'tag',) - depth = 1 - - -class CoreSkillRecordSerializer(serializers.ModelSerializer): - """Serializer for Core Skill Record""" - - class Meta: - model = CoreSkillRecord - fields = ('id', 'skill', 'level', ) - depth = 1 - -class StudentNotesSerializer(serializers.ModelSerializer): - """Serializer for Core Skill Record""" - - class Meta: - model = StudentNote - fields = ('id', 'note', 'created_on', 'author') - - -class MicroStudents(serializers.ModelSerializer): - """JSON serializer""" - tags = StudentTagSerializer(many=True) - notes = StudentNotesSerializer(many=True) - avatar = serializers.SerializerMethodField() - - def get_avatar(self, obj): - github = obj.user.socialaccount_set.get(user=obj.user) - return github.extra_data["avatar_url"] - - - class Meta: - model = NssUser - fields = ('id', 'name', 'score', 'tags', - 'book', 'assessment_status', 'proposals', - 'github_handle', 'current_cohort', - 'assessment_overview', 'notes', 'avatar', - ) - - -class SingleStudent(serializers.ModelSerializer): - """JSON serializer""" - feedback = StudentNoteSerializer(many=True) - name = serializers.SerializerMethodField() - email = serializers.SerializerMethodField() - github = serializers.SerializerMethodField() - repos = serializers.SerializerMethodField() - staff = serializers.SerializerMethodField() - date_joined = serializers.SerializerMethodField() - - def get_date_joined(self, obj): - return obj.user.date_joined - - def get_staff(self, obj): - return False - - def get_github(self, obj): - github = obj.user.socialaccount_set.get(user=obj.user) - return github.extra_data["login"] - - def get_repos(self, obj): - github = obj.user.socialaccount_set.get(user=obj.user) - return github.extra_data["repos_url"] - - def get_name(self, obj): - return f'{obj.user.first_name} {obj.user.last_name}' - - def get_email(self, obj): - return obj.user.email - - class Meta: - model = NssUser - fields = ('id', 'name', 'email', 'github', 'staff', 'slack_handle', - 'cohorts', 'feedback', 'repos', 'score', 'date_joined', - 'current_cohort', ) From 273705b53658c706e665e0c8f0696b18a099e3a2 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Sun, 18 Feb 2024 17:50:05 -0600 Subject: [PATCH 10/11] Added new notify function so client can send notication to Learning Platform channel --- LearningAPI.session.sql | 282 +---------------------------- LearningAPI/views/__init__.py | 1 + LearningAPI/views/capstone_view.py | 2 +- LearningAPI/views/notify.py | 47 +++++ LearningPlatform/urls.py | 1 + 5 files changed, 54 insertions(+), 279 deletions(-) create mode 100644 LearningAPI/views/notify.py diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index a27025e..534a156 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -1,283 +1,5 @@ - -SELECT * -FROM public."LearningAPI_cohort"; - - -SELECT * -FROM public."LearningAPI_opportunity"; - - -SELECT * -FROM public."LearningAPI_learningrecord"; - - -SELECT * -FROM public."socialaccount_socialaccount"; - - -SELECT * -FROM public."auth_user" -ORDER BY id DESC; - - -SELECT * -FROM public."LearningAPI_studentassessment"; - - -SELECT * -FROM public."authtoken_token"; - - -DELETE -FROM public."LearningAPI_cohortcourse"; - - -SELECT * -FROM public."LearningAPI_course"; - - -SELECT * -FROM public."LearningAPI_studenttag"; - - -DELETE -FROM public."LearningAPI_studenttag"; - - -SELECT * -FROM public."LearningAPI_cohort"; - - -SELECT * -FROM public."LearningAPI_cohortcourse"; - - -insert into public."LearningAPI_cohortcourse" (cohort_id, - course_id, - active) -values (3, - 1, - FALSE); - - -insert into public."LearningAPI_cohortcourse" (cohort_id, - course_id, - active) -values (3, - 3, - TRUE); - - select * from pg_catalog.pg_tables; - - -SELECT * -FROM public."LearningAPI_studentpersonality"; - - -DELETE -FROM public."LearningAPI_cohort" -where id = 12; - - -DELETE -FROM public."LearningAPI_cohortcourse"; - - -UPDATE public."LearningAPI_nssuser" -SET slack_handle = 'G08NYBJSY' ; - - -UPDATE public."LearningAPI_studentpersonality" -SET briggs_myers_type = 'ESTJ' -WHERE student_id = 56; - - -INSERT INTO public."LearningAPI_studentpersonality" (student_id, - briggs_myers_type, - bfi_extraversion, - bfi_agreeableness, - bfi_conscientiousness, - bfi_neuroticism, - bfi_openness) -VALUES (56, - 'ENTJ-A', - 69, - 96, - 73, - 0, - 94); - - -SELECT * -FROM public."LearningAPI_capstone"; - - -SELECT * -FROM public."LearningAPI_proposalstatus"; - - -INSERT INTO public."LearningAPI_capstonetimeline" (capstone_id, - status_id, date) -VALUES (3, - 1, - '2022-11-04'); - - -INSERT INTO public."LearningAPI_capstone" (proposal_url, - repo_url, - course_id, - student_id, - description) -VALUES ('http://www.claire.com', - 'http://www.claire.com', - 3, - 56, - 'Client side capstone proposal'); - - -SELECT "LearningAPI_cohort"."id", - "LearningAPI_cohort"."name", - "LearningAPI_cohort"."slack_channel", - "LearningAPI_cohort"."start_date", - "LearningAPI_cohort"."end_date", - "LearningAPI_cohort"."break_start_date", - "LearningAPI_cohort"."break_end_date", - COUNT("LearningAPI_nssusercohort"."id") FILTER ( - WHERE NOT "auth_user"."is_staff" ) AS "students", - COUNT("LearningAPI_nssusercohort"."id") FILTER ( - WHERE "auth_user"."is_staff" ) AS "instructors" -FROM "LearningAPI_cohort" -LEFT OUTER JOIN "LearningAPI_nssusercohort" ON ("LearningAPI_cohort"."id" = "LearningAPI_nssusercohort"."cohort_id") -LEFT OUTER JOIN "LearningAPI_nssuser" ON ("LearningAPI_nssusercohort"."nss_user_id" = "LearningAPI_nssuser"."id") -LEFT OUTER JOIN "auth_user" ON ("LearningAPI_nssuser"."user_id" = "auth_user"."id") -GROUP BY "LearningAPI_cohort"."id" ; - - -SELECT "LearningAPI_capstone"."id", - "LearningAPI_capstone"."student_id", - "LearningAPI_capstone"."course_id", - "LearningAPI_capstone"."proposal_url", - "LearningAPI_capstone"."repo_url", - "LearningAPI_capstone"."description", - COUNT("LearningAPI_capstonetimeline"."id") AS "status_count", - COUNT("LearningAPI_capstonetimeline"."id") FILTER ( - WHERE "LearningAPI_proposalstatus"."status" = Approved) AS "approved" -FROM "LearningAPI_capstone" -LEFT OUTER JOIN "LearningAPI_capstonetimeline" ON ("LearningAPI_capstone"."id" = "LearningAPI_capstonetimeline"."capstone_id") -LEFT OUTER JOIN "LearningAPI_proposalstatus" ON ("LearningAPI_capstonetimeline"."status_id" = "LearningAPI_proposalstatus"."id") -WHERE "LearningAPI_capstone"."student_id" = 74 -GROUP BY "LearningAPI_capstone"."id" ; - - -select w.id, - w.label, - w.weight, - w.tier, - r.achieved, - r.student_id -from public."LearningAPI_learningweight" w -left outer join public."LearningAPI_learningrecord" r on r.weight_id = w.id -and r.student_id = 19 -where r.achieved is NULL -order by w.tier; - - -SELECT "LearningAPI_book"."id", - "LearningAPI_book"."name", - "LearningAPI_book"."course_id", - "LearningAPI_book"."description", - "LearningAPI_book"."index" -FROM "LearningAPI_book" -ORDER BY "LearningAPI_book"."course_id" ASC, - "LearningAPI_book"."index" ASC ; - - -SELECT COUNT("LearningAPI_capstonetimeline"."id") AS "status_count", - COUNT("LearningAPI_capstonetimeline"."id") FILTER ( - WHERE "LearningAPI_proposalstatus"."status" = 'Approved') AS approved, - COUNT("LearningAPI_capstonetimeline"."id") FILTER ( - WHERE "LearningAPI_proposalstatus"."status" = 'MVP') AS mvp, - CASE - WHEN COUNT("LearningAPI_capstonetimeline"."id") = 0 THEN 'submitted' - WHEN (COUNT("LearningAPI_capstonetimeline"."id") > 0 - AND COUNT("LearningAPI_capstonetimeline"."id") FILTER ( - WHERE ("LearningAPI_proposalstatus"."status" = 'MVP')) = 1) THEN 'mvp' - WHEN (COUNT("LearningAPI_capstonetimeline"."id") > 0 - AND COUNT("LearningAPI_capstonetimeline"."id") FILTER ( - WHERE ("LearningAPI_proposalstatus"."status" = 'Approved')) = 0) THEN 'reviewed' - WHEN (COUNT("LearningAPI_capstonetimeline"."id") > 0 - AND COUNT("LearningAPI_capstonetimeline"."id") FILTER ( - WHERE ("LearningAPI_proposalstatus"."status" = 'Approved')) = 1) THEN 'approved' - ELSE 'unsubmitted' - END AS current_status -FROM "LearningAPI_capstone" -LEFT OUTER JOIN "LearningAPI_capstonetimeline" ON ("LearningAPI_capstone"."id" = "LearningAPI_capstonetimeline"."capstone_id") -LEFT OUTER JOIN "LearningAPI_proposalstatus" ON ("LearningAPI_capstonetimeline"."status_id" = "LearningAPI_proposalstatus"."id") -WHERE "LearningAPI_capstone"."student_id" = 291 -GROUP BY "LearningAPI_capstone"."id" ; - - -SELECT * -FROM get_project_average_start_delay(1); - - -select * -from "LearningAPI_course"; - - -SELECT book.name AS "BookName", - book.index AS "BookIndex", - project.name AS "ProjectName", - project.index AS "ProjectIndex", - AVG(student_project.date_created - cohort.start_date) AS "AverageStartDelay" -FROM "LearningAPI_studentproject" AS student_project -INNER JOIN "LearningAPI_project" AS project ON student_project.project_id = project.id -INNER JOIN "LearningAPI_book" AS book ON project.book_id = book.id -INNER JOIN "LearningAPI_nssusercohort" AS nssusercohort ON student_project.student_id = nssusercohort.nss_user_id -INNER JOIN "LearningAPI_cohort" AS cohort ON nssusercohort.cohort_id = cohort.id -INNER JOIN "LearningAPI_course" AS course ON book.course_id = course.id -WHERE course.id = 3 -GROUP BY book.index, - book.name, - project.index, - project.name -ORDER BY book.index, - project.index ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -432,6 +154,10 @@ $$ LANGUAGE plpgsql; + + + + diff --git a/LearningAPI/views/__init__.py b/LearningAPI/views/__init__.py index 8e3c05f..ed97be0 100644 --- a/LearningAPI/views/__init__.py +++ b/LearningAPI/views/__init__.py @@ -4,6 +4,7 @@ from .student_view import StudentViewSet from .auth import register_user from .auth import login_user +from .notify import notify from .course_view import CourseViewSet from .book_view import BookViewSet from .project_view import ProjectViewSet diff --git a/LearningAPI/views/capstone_view.py b/LearningAPI/views/capstone_view.py index 12dee6d..d48a0f0 100644 --- a/LearningAPI/views/capstone_view.py +++ b/LearningAPI/views/capstone_view.py @@ -45,7 +45,7 @@ def create(self, request): try: Capstone.objects.get(student=student, course=course) - return Response({'message': 'You have already submittted a proposal for this course. If you made updates, just let your instructional team know via Slack'}, status=status.HTTP_400_BAD_REQUEST) + return Response({'message': 'You have already submitted a proposal for this course. If you made updates, just let your instructional team know via Slack'}, status=status.HTTP_400_BAD_REQUEST) except Capstone.DoesNotExist: proposal = Capstone() proposal.course = course diff --git a/LearningAPI/views/notify.py b/LearningAPI/views/notify.py new file mode 100644 index 0000000..08861e7 --- /dev/null +++ b/LearningAPI/views/notify.py @@ -0,0 +1,47 @@ +import os +import requests +from rest_framework.decorators import api_view +from rest_framework.response import Response +from LearningAPI.models.people import NssUser + +@api_view(['POST']) +def notify(request): + """ + Sends a notification message to a Slack channel. + + Args: + request (HttpRequest): The HTTP request object. + + Returns: + Response: The HTTP response object with a success message. + + Raises: + NssUser.DoesNotExist: If the NssUser object does not exist. + AttributeError: If the user attribute is not present in the request's auth object. + IndexError: If the assigned_cohorts queryset is empty. + AttributeError: If the cohort attribute is not present in the first assigned_cohorts object. + AttributeError: If the slack_channel attribute is not present in the cohort object. + requests.exceptions.Timeout: If the request to the Slack API times out. + """ + + student = NssUser.objects.get(user=request.auth.user) + slack_channel = student.assigned_cohorts.order_by("-id").first().cohort.slack_channel + + message = request.data.get("message") + + headers = { + "Content-Type": "application/x-www-form-urlencoded" + } + + requests.post( + "https://slack.com/api/chat.postMessage", + data={ + "text": message, + "token": os.getenv("SLACK_BOT_TOKEN"), + "channel": slack_channel + }, + headers=headers, + timeout=10 + ) + + return Response({ 'message': 'Notification sent to Slack!'}, status=200) diff --git a/LearningPlatform/urls.py b/LearningPlatform/urls.py index 19e3518..9582979 100644 --- a/LearningPlatform/urls.py +++ b/LearningPlatform/urls.py @@ -55,6 +55,7 @@ path('records/entries/', views.LearningRecordViewSet.as_view({'delete': 'entries'}), name="entries"), path('accounts', views.register_user), + path('notify', views.notify, name='notify'), path('accounts/verify', rest_views.obtain_auth_token, name='api-token-auth'), path('auth/', include('dj_rest_auth.urls')), From f5a7d450c5874e7b5f50bf3634484a373d4d0ec5 Mon Sep 17 00:00:00 2001 From: Steve Brownlee Date: Sun, 18 Feb 2024 21:09:41 -0600 Subject: [PATCH 11/11] Cast null scores as 0 --- LearningAPI.session.sql | 6 +++--- LearningAPI/admin.py | 2 ++ .../migrations/0041_students_by_cohort_db_function.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/LearningAPI.session.sql b/LearningAPI.session.sql index 534a156..a037e49 100644 --- a/LearningAPI.session.sql +++ b/LearningAPI.session.sql @@ -46,7 +46,7 @@ SELECT b.id::int AS current_book_id, b.index::int AS current_book_index, b.name::text AS current_book_name, - lr.total_score::int AS score, + COALESCE(lr.total_score, 0)::int AS score, COALESCE( json_agg( json_build_object( @@ -165,8 +165,8 @@ $$ LANGUAGE plpgsql; SELECT nu.user_id::int, nu.github_handle::text, - social.extra_data::text, au."first_name" || ' ' || au."last_name" AS student_name, + social.extra_data::text, c.name::text AS current_cohort, c.id::int AS current_cohort_id, COALESCE(sa.status_id::int, 0) AS assessment_status_id, @@ -176,7 +176,7 @@ SELECT b.id::int AS current_book_id, b.index::int AS current_book_index, b.name::text AS current_book_name, - lr.total_score::int AS score, + COALESCE(lr.total_score, 0)::int AS score, COALESCE( json_agg( json_build_object( diff --git a/LearningAPI/admin.py b/LearningAPI/admin.py index 46af47d..5b65da5 100644 --- a/LearningAPI/admin.py +++ b/LearningAPI/admin.py @@ -119,11 +119,13 @@ class LearningWeightAdmin(admin.ModelAdmin): class LearningRecordAdmin(admin.ModelAdmin): """Learning records""" list_display = ('student', 'weight',) + search_fields = ["student__user__last_name"] @admin.register(LearningRecordEntry) class LearningRecordEntryAdmin(admin.ModelAdmin): """Learning record entries""" list_display = ('record', 'instructor', 'note',) + search_fields = ["record__student__user__last_name"] @admin.register(NssUser) class NssUserAdmin(admin.ModelAdmin): diff --git a/LearningAPI/migrations/0041_students_by_cohort_db_function.py b/LearningAPI/migrations/0041_students_by_cohort_db_function.py index 574d5b4..f993797 100644 --- a/LearningAPI/migrations/0041_students_by_cohort_db_function.py +++ b/LearningAPI/migrations/0041_students_by_cohort_db_function.py @@ -47,7 +47,7 @@ class Migration(migrations.Migration): b.id::int AS current_book_id, b.index::int AS current_book_index, b.name::text AS current_book_name, - lr.total_score::int AS score, + COALESCE(lr.total_score, 0)::int AS score, COALESCE( json_agg( json_build_object(