diff --git a/Makefile b/Makefile index 13e5e7e..864a1df 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,6 @@ upload_test: scp -r ./build learningassistants@cse.unl.edu:~/public_html/LA-Feedback-Test ssh learningassistants@cse.unl.edu "mkdir ~/public_html/LA-Feedback-Test/log; chmod 700 public_html/LA-Feedback-Test/data/ public_html/LA-Feedback-Test/log public_html/LA-Feedback-Test/programUpdate.php" - clean: rm -rf ./build diff --git a/package.json b/package.json index 88d1832..39afe9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "la-feedback-system", - "version": "2.2.0", + "version": "3.0.0", "repository": "https://github.com/hbiede/LA-Feedback-System", "readme": "./README.md", "private": true, diff --git a/public/addStudents.php b/public/addStudents.php index 55536c8..7bc3c93 100644 --- a/public/addStudents.php +++ b/public/addStudents.php @@ -2,7 +2,7 @@ // To get list of interaction counts per LA: // Call with a POST call with a JSON body as follows: //{ -// username: string (The new students with the text formatted as below), +// students: string (The new students with the text formatted as below), //} // This student list is expected to be formatted with every line conforming to the following spec: diff --git a/public/admin.php b/public/admin.php index 751212c..cbac23a 100644 --- a/public/admin.php +++ b/public/admin.php @@ -127,7 +127,7 @@ function get_outstanding_feedback() { function get_interactions() { $conn = get_connection(); - $ps = $conn->prepare('SELECT username, CONCAT(name, IF(is_admin, \' (Admin)\', \'\')) AS \'name\', ' . + $ps = $conn->prepare('SELECT IFNULL(canvas_username, username) AS \'username\', CONCAT(name, IF(is_admin, \' (Admin)\', \'\')) AS \'name\', ' . 'cse_usernames.course, COUNT(i.interaction_key) AS count, COUNT(t.interaction_key) AS wCount, ' . 'COUNT(f.feedback_key) AS fCount, ' . 'AVG(rating) AS avg, AVG(sentiment) AS sentiment FROM cse_usernames ' . diff --git a/public/breakdown.php b/public/breakdown.php index e2819a8..ac86a7a 100644 --- a/public/breakdown.php +++ b/public/breakdown.php @@ -22,9 +22,9 @@ function get_interaction_counts() { $conn = get_connection(); - $ps = $conn->prepare('SELECT username, name, c.course, COUNT(i.interaction_key) AS count, ' . + $ps = $conn->prepare('SELECT canvas_username AS \'username\', name, c.course, COUNT(i.interaction_key) AS count, ' . 'SUM(IF(i.time_of_interaction >= (CURRENT_DATE() - INTERVAL 7 DAY), 1, 0)) AS wcount FROM interactions i ' . - 'LEFT JOIN cse_usernames c on c.username_key = i.la_username_key GROUP BY username'); + 'LEFT JOIN cse_usernames c on c.username_key = i.la_username_key GROUP BY username, canvas_username'); $returnVal = []; if ($ps) { $ps->execute(); diff --git a/public/course.php b/public/course.php index fe441e4..c5848b0 100644 --- a/public/course.php +++ b/public/course.php @@ -29,7 +29,7 @@ function get_course($username) { $conn = get_connection(); $response = ''; - $ps = $conn->prepare('SELECT course FROM cse_usernames WHERE username=?;'); + $ps = $conn->prepare('SELECT course FROM cse_usernames WHERE canvas_username=?;'); if ($ps) { $ps->bind_param('s', $username); $ps->execute(); @@ -49,7 +49,7 @@ function get_course($username) { function set_course($username, $course) { get_username_id($username); $conn = get_connection(); - $ps = $conn->prepare('UPDATE cse_usernames SET course=? WHERE username=?;'); + $ps = $conn->prepare('UPDATE cse_usernames SET course=? WHERE canvas_username=?;'); if ($ps) { $ps->bind_param('ss', $course, $username); $ps->execute(); diff --git a/public/courseList.php b/public/courseList.php index 2faf4f0..baba114 100644 --- a/public/courseList.php +++ b/public/courseList.php @@ -9,4 +9,15 @@ // To get list of courses in the program: // Call with a GET call. Result will be an array of strings -echo file_get_contents("./data/courses.json"); +ini_set('error_log', './log/courseList.log'); +include_once 'sqlManager.php'; + +function get_courses() { + $course_assoc = run_accessor('SELECT DISTINCT course FROM cse_usernames WHERE course IS NOT NULL ORDER BY course'); + $returnVal = []; + foreach ($course_assoc as $course) { + array_push($returnVal, $course['course']); + } + return $returnVal; +} +echo json_encode(get_courses()); diff --git a/public/data/tableSetup.sql b/public/data/tableSetup.sql index c8f45f3..e7bc437 100755 --- a/public/data/tableSetup.sql +++ b/public/data/tableSetup.sql @@ -21,8 +21,9 @@ drop view if exists interaction_type_readable; CREATE TABLE cse_usernames ( username_key int auto_increment unique primary key, + canvas_username varchar(30) not null, + # used for CSE usernames username varchar(20), - canvas_username varchar(20), name varchar(70), course varchar(10), email varchar(100), diff --git a/public/feedbackDownload.php b/public/feedbackDownload.php index 28bd79b..ae5c69f 100644 --- a/public/feedbackDownload.php +++ b/public/feedbackDownload.php @@ -5,7 +5,7 @@ function send_csv() { $conn = get_connection(); - $ps = $conn->prepare('SELECT IFNULL(name, username) AS "LA", rating, comment, cu.course, ' . + $ps = $conn->prepare('SELECT IFNULL(name, IFNULL(canvas_username, username)) AS "LA", rating, comment, cu.course, ' . 'IFNULL(CONCAT(sentiment, "%"), "") AS sentiment, interaction_type, time_of_interaction FROM feedback ' . 'LEFT JOIN interactions i on feedback.interaction_key = i.interaction_key LEFT JOIN cse_usernames cu on ' . 'i.la_username_key = cu.username_key ORDER BY username, time_of_interaction;'); diff --git a/public/form.php b/public/form.php index 9e24439..955e530 100644 --- a/public/form.php +++ b/public/form.php @@ -19,7 +19,7 @@ function get_id() { } if (!can_give_feedback(get_id())) { - header('Location: https://cse.unl.edu/~learningassistants/LA-Feedback/thankyou.html'); + header('Location: ' . str_replace('form.php', 'thankyou.html', get_url())); } ?> @@ -38,7 +38,7 @@ function get_id() { const START_TIME = new Date(); const onSuccess = () => { - window.location.href = 'https://cse.unl.edu/~learningassistants/LA-Feedback/thankyou.html'; + window.location.href = ''; }; const onError = () => { @@ -61,7 +61,7 @@ function validateSubmit() { const time = new Date() - START_TIME; if (id && id >= 0) { $.ajax({ - url: `https://cse.unl.edu/~learningassistants/LA-Feedback/submitFeedback.php`, + url: '', method: "POST", data: { id, diff --git a/public/getStudents.php b/public/getStudents.php index af3d57c..e2c43a8 100644 --- a/public/getStudents.php +++ b/public/getStudents.php @@ -20,10 +20,10 @@ function get_students() { return run_accessor('SELECT c.username_key AS id, c.username, c.name, c.course, c.canvas_username, ' . 'COUNT(i.interaction_key) AS \'interaction_count\' FROM cse_usernames c LEFT JOIN interactions i ' . - 'on c.username_key = i.student_username_key GROUP BY username_key;'); + 'ON c.username_key = i.student_username_key GROUP BY username_key;'); } $response = [ 'students' => get_students(), ]; -echo json_encode($response); \ No newline at end of file +echo json_encode($response); diff --git a/public/name.php b/public/name.php index f6c93dc..89abd81 100644 --- a/public/name.php +++ b/public/name.php @@ -29,7 +29,7 @@ function get_name($username) { $conn = get_connection(); $response = ''; - $ps = $conn->prepare('SELECT name FROM cse_usernames WHERE username=?;'); + $ps = $conn->prepare('SELECT name FROM cse_usernames WHERE canvas_username=?;'); if ($ps) { $ps->bind_param('s', $username); $ps->execute(); @@ -49,7 +49,7 @@ function get_name($username) { function set_name($username, $name) { get_username_id($username); $conn = get_connection(); - $ps = $conn->prepare('UPDATE cse_usernames SET name=? WHERE username=?;'); + $ps = $conn->prepare('UPDATE cse_usernames SET name=? WHERE canvas_username=?;'); if ($ps) { $ps->bind_param('ss', $name, $username); $ps->execute(); diff --git a/public/programUpdate.php b/public/programUpdate.php index 17079e0..a7c8b29 100755 --- a/public/programUpdate.php +++ b/public/programUpdate.php @@ -75,7 +75,7 @@ function get_course_averages($days) { function get_feedback($days = DAYS) { $conn = get_connection(); $ps = $conn->prepare('SELECT DATE_FORMAT(time_of_interaction, \'%Y-%m-%dT%TZ\') AS time, ' . - 'interaction_type, sentiment, IFNULL(name, username) AS LA, rating, ' . + 'interaction_type, sentiment, IFNULL(name, IFNULL(canvas_username, username)) AS LA, rating, ' . 'comment, cu.course AS "course" FROM feedback LEFT JOIN interactions i ' . 'on feedback.interaction_key = i.interaction_key ' . 'LEFT JOIN cse_usernames cu on i.la_username_key = cu.username_key ' . diff --git a/public/sqlManager.php b/public/sqlManager.php index 5d3882a..5edcfe5 100644 --- a/public/sqlManager.php +++ b/public/sqlManager.php @@ -5,6 +5,10 @@ * File created by Hundter Biede for the UNL CSE Learning Assistant Program */ +function get_url() { + return 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; +} + function get_connection() { $sql_info = json_decode(file_get_contents("data/sql.json")); $conn = new mysqli($sql_info->{'url'}, $sql_info->{'username'}, $sql_info->{'password'}); @@ -23,7 +27,8 @@ function get_connection() { function get_name_from_interaction($interaction_id) { $conn = get_connection(); - $ps = $conn->prepare('SELECT username,name FROM cse_usernames WHERE username_key=(SELECT la_username_key FROM interactions WHERE interaction_key = ?);'); + $ps = $conn->prepare("SELECT IFNULL(canvas_username, username) AS 'username',name FROM cse_usernames WHERE " . + "username_key=(SELECT la_username_key FROM interactions WHERE interaction_key = ?);"); if (!$ps) { error_log('Failed to build prepped statement'); $conn->close(); @@ -82,14 +87,14 @@ function get_interaction_type_from_interaction($interaction_id) { function get_la_username_from_interaction($interaction_id) { return get_username_from_interaction( - 'SELECT username FROM cse_usernames WHERE username_key=(SELECT la_username_key FROM interactions WHERE interaction_key = ?);', + 'SELECT canvas_username AS \'username\' FROM cse_usernames WHERE username_key=(SELECT la_username_key FROM interactions WHERE interaction_key = ?);', $interaction_id ); } function get_student_username_from_interaction($interaction_id) { return get_username_from_interaction( - 'SELECT username FROM cse_usernames WHERE username_key=(SELECT student_username_key FROM interactions WHERE interaction_key = ?);', + 'SELECT canvas_username AS \'username\' FROM cse_usernames WHERE username_key=(SELECT student_username_key FROM interactions WHERE interaction_key = ?);', $interaction_id ); } @@ -135,13 +140,13 @@ function can_give_feedback($interaction_id) { return $can_give && !$given; } -function add_cse($username) { +function add_cse($username, $email = null) { $conn = get_connection(); if ($conn !== null) { $conn->begin_transaction(); - $ps = $conn->prepare("INSERT INTO cse_usernames (username) VALUE (?);"); + $ps = $conn->prepare("INSERT INTO cse_usernames (canvas_username, email) VALUE (?, ?);"); if ($ps) { - $ps->bind_param("s", $username); + $ps->bind_param("ss", $username, $email); $ps->execute(); $return_val = $ps->insert_id; $conn->commit(); @@ -213,7 +218,7 @@ function has_been_a_week($username) { $conn = get_connection(); if ($conn !== null) { $ps = $conn->prepare("SELECT COUNT(*) AS 'count' FROM interactions " . - "LEFT JOIN cse_usernames cu ON cu.username_key = interactions.la_username_key WHERE cu.username = ? " . + "LEFT JOIN cse_usernames cu ON cu.username_key = interactions.la_username_key WHERE cu.canvas_username = ? " . "AND time_of_interaction > (CURRENT_DATE() - INTERVAL 7 DAY)"); if ($ps) { $ps->bind_param("s", $username); @@ -271,12 +276,13 @@ function received_email_today($student_id) { return false; } -function get_username_id($username) { +function get_username_id($username, $email = null) { if ($username === null || strlen(trim($username)) === 0) return null; $conn = get_connection(); if ($conn !== null) { - $ps = $conn->prepare("SELECT username_key FROM cse_usernames WHERE username = ?;"); + $ps = $conn->prepare("SELECT username_key FROM cse_usernames WHERE canvas_username = ? " . + "ORDER BY username_key LIMIT 1;"); if (!$ps) { error_log("Failed to build prepped statement for getting username ID for $username"); $conn->close(); @@ -290,7 +296,7 @@ function get_username_id($username) { error_log('INFO: { la_username: ' . $username . ', la_id: ' . $id . ' }'); $ps->fetch(); if ($id === null) { - $id = add_cse($username); + $id = add_cse($username, $email); } $ps->close(); $conn->close(); @@ -343,8 +349,11 @@ function run_accessor($query) { } function is_admin($user) { + if ($user == get_current_user()) { + return true; + } $conn = get_connection(); - $ps = $conn->prepare("SELECT is_admin FROM cse_usernames WHERE username=?;"); + $ps = $conn->prepare("SELECT is_admin FROM cse_usernames WHERE canvas_username=?;"); $result = false; if ($ps) { $ps->bind_param("s", $user); @@ -362,8 +371,9 @@ function is_admin($user) { } function get_admins() { - return run_accessor("SELECT username_key AS 'id', username FROM cse_usernames WHERE is_admin UNION " . - "SELECT -1, 'learningassistants';"); + $super_admin = get_current_user(); + return run_accessor("SELECT username_key AS 'id', canvas_username AS 'username' FROM cse_usernames WHERE is_admin UNION " . + "SELECT -1, '$super_admin';"); } function update_admin($is_admin, $user_key) { diff --git a/public/ticketAccessor.php b/public/ticketAccessor.php index 9441c00..928e156 100644 --- a/public/ticketAccessor.php +++ b/public/ticketAccessor.php @@ -16,17 +16,18 @@ // Returns a string of the username -$casService = 'https://cse-apps.unl.edu/cas'; -$thisService = 'https://cse.unl.edu/~learningassistants/LA-Feedback'; +$casService = 'https://shib.unl.edu/idp/profile/cas'; +$thisService = get_url(); -function addLogin($username) { +function add_login($username, $email) { error_log("Attempting to log $username"); + $la_id = get_username_id($username, $email); $conn = get_connection(); if ($conn !== null) { $conn->begin_transaction(); - $ps = $conn->prepare("INSERT INTO logins (la_username_key) VALUE ((SELECT username_key FROM cse_usernames WHERE username=?));"); + $ps = $conn->prepare("INSERT INTO logins (la_username_key) VALUE (?);"); if ($ps) { - $ps->bind_param("s", $username); + $ps->bind_param("i", $la_id); $ps->execute(); if ($ps->error) { error_log("Failed to log $username"); @@ -78,7 +79,8 @@ function responseForTicket($ticket) { if ($response = responseForTicket($obj->{'ticket'})) { $xml = simplexml_load_string($response); $user = $xml->children('http://www.yale.edu/tp/cas')->authenticationSuccess->user[0]; - addLogin($user); + $email = $xml->children('http://www.yale.edu/tp/cas')->authenticationSuccess->user[0]->attributes->email[0]; + add_login($user, $email); echo $user; } else { echo 'INVALID_TICKET_KEY'; diff --git a/src/App.tsx b/src/App.tsx index 369c096..1429349 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -24,22 +24,28 @@ import FeedbackHeader from 'components/FeedbackHeader'; import styles from './App.styles'; function App() { - const { loading, isAdmin, response, setResponse } = Redux( + const { + loading, + isAdmin, + response, + setResponse, + setSelectedUsername, + } = Redux( (state) => ({ loading: state.loading, isAdmin: state.isAdmin, response: state.response, setResponse: state.setResponse, - username: state.username, + setSelectedUsername: state.setSelectedUsername, }), shallow ); const [adminAsLA, setAdminAsLA] = useState(false); - const toggleAdminAsLA = useCallback(() => setAdminAsLA(!adminAsLA), [ - setAdminAsLA, - adminAsLA, - ]); + const toggleAdminAsLA = useCallback(() => { + setSelectedUsername({ username: '' }); + setAdminAsLA(!adminAsLA); + }, [setAdminAsLA, adminAsLA]); const AdminScreen = React.lazy(() => import('screens/AdminScreen')); const loadingLabel =

Loading

; diff --git a/src/CHANGELOG.json b/src/CHANGELOG.json index d1e538b..f69b560 100644 --- a/src/CHANGELOG.json +++ b/src/CHANGELOG.json @@ -1,5 +1,6 @@ { "changes": [ + "## 3.0.0\n- Convert to UNL's authentication system", "## 2.2.1\n- Fix error with removing admins", "## 2.2.0\n- Display students on the admin page\n- Add the ability to add new students to the database from the frontend\n- Add directions for admins to be able to reset the entire system\n- Allow admins to add/remove other admins from the page\n- Allow full reset of page by an admin", "## 2.1.0\n- Add login records table to admin view\n- Prevent viewing feedback from LAs who have not received feedback", diff --git a/src/components/AdminComponents/LAFeedbackTable.tsx b/src/components/AdminComponents/LAFeedbackTable.tsx index 05a8e91..263d01c 100644 --- a/src/components/AdminComponents/LAFeedbackTable.tsx +++ b/src/components/AdminComponents/LAFeedbackTable.tsx @@ -76,6 +76,7 @@ const LAFeedbackTable = () => { const showLA = useCallback( (la: LA) => { if ( + la && ( interactions.ratings.find( (rating) => rating.username === la.username diff --git a/src/redux/actions/GetCourses.ts b/src/redux/actions/GetCourses.ts index 8a78cc7..05c1229 100644 --- a/src/redux/actions/GetCourses.ts +++ b/src/redux/actions/GetCourses.ts @@ -4,6 +4,8 @@ - File created by Hundter Biede for the UNL CSE Learning Assistant Program -----------------------------------------------------------------------------*/ +import { api } from 'redux/modules'; + import ServiceInterface from 'statics/ServiceInterface'; /** @@ -23,6 +25,12 @@ const getCourses = async (): Promise => { .then((response: Response) => response.json()) .then((json) => { result = json; + if (result.length === 0) { + api.getState().setResponse({ + class: 'danger', + content: 'No courses in database', + }); + } }); return result; }; diff --git a/src/redux/modules/Types.ts b/src/redux/modules/Types.ts index b10c8de..424b40d 100644 --- a/src/redux/modules/Types.ts +++ b/src/redux/modules/Types.ts @@ -34,8 +34,8 @@ export const ALERT_CLASSES = [ export type ResponseClass = typeof ALERT_CLASSES[number]; export type ResponseMessage = { - class: ResponseClass; - content: string | JSX.Element; + class?: ResponseClass; + content?: string | JSX.Element; /** * @default true */ diff --git a/src/screens/FeedbackForm.tsx b/src/screens/FeedbackForm.tsx index 6c2ab13..0a5d00e 100644 --- a/src/screens/FeedbackForm.tsx +++ b/src/screens/FeedbackForm.tsx @@ -31,7 +31,7 @@ const COURSE_ID = 'course'; const STUDENT_ID = 'student_login'; const INTERACTION_TYPE_ID = 'interaction_type'; -const LA_LABEL = 'LA CSE Username'; +const LA_LABEL = 'LA Canvas Username'; const COURSE_LABEL = 'Course'; const STUDENT_LABEL = 'Student'; const INTERACTION_TYPE_LABEL = 'Interaction Type'; diff --git a/src/statics/ServiceInterface.ts b/src/statics/ServiceInterface.ts index 13ccaae..4ff82d1 100644 --- a/src/statics/ServiceInterface.ts +++ b/src/statics/ServiceInterface.ts @@ -8,7 +8,7 @@ import { api } from 'redux/modules'; import { RESTResponse } from 'statics/Types'; -const CSE_CAS_SERVICE = 'https://cse-apps.unl.edu/cas'; +const CSE_CAS_SERVICE = 'https://shib.unl.edu/idp/profile/cas'; class ServiceInterface { /**