Skip to content

Commit

Permalink
Get stats when specifying courses.
Browse files Browse the repository at this point in the history
  • Loading branch information
GiridharRNair committed Nov 22, 2023
1 parent 107f8ca commit 8d20b5c
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 73 deletions.
26 changes: 26 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.env
**/__pycache__
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?
*.env
*.env
*/__pycache__
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ FROM python:3.10

WORKDIR /app

# Upgrade pip
RUN pip install --no-cache-dir --upgrade pip

# Copy only the requirements file first to leverage Docker cache
COPY ./server/requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

COPY ./server/* /app/
# Copy the entire application code
COPY ./server/ .

# Expose port 80
EXPOSE 80

CMD ["gunicorn", "--bind", "0.0.0.0:80", "--workers", "4", "--threads", "4", "--timeout", "120", "main:app"]
2 changes: 1 addition & 1 deletion extension/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ProfStatsUTD Frontend

ProfStatsUTD is a Chrome extension that provides a convenient way to view professor ratings and grade distributions from UT Dallas's ProfStatsUTD backend. The frontend is built using Chakra UI and Vite.
This is the frontend code for ProfStatsUTD, a Chrome extension that provides aggregated grades and professor ratings for courses at The University of Texas at Dallas (UTD), built using Chakra UI and Vite.

## Environment Variables
To run the YourDailyRundown Frontend, you'll need to set the following environment variables:
Expand Down
Binary file added extension/public/ProfStatsUTDIcon128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 3 additions & 12 deletions extension/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,20 @@
"manifest_version": 3,
"name": "ProfStats UT Dallas",
"version": "1.0",
"description": "This extension shows professor ratings from RateMyProfessor.com and sources grade distributions from UTDgrades.com",
"description": "ProfStatsUTD is a comprehensive Chrome extension designed to streamline your academic experience at The University of Texas at Dallas (UTD). The extension offers a user-friendly interface for accessing aggregated grades and professor ratings effortlessly.",
"action": {
"default_popup": "index.html",
"default_title": "ProfStats"
},
"permissions": [
"tabs",
"scripting",
"http://*/",
"https://*/"
],
"host_permissions": [
"https://*/*"
],
"icons": {
"48": "vite.svg",
"128": "vite.svg"
},
"web_accessible_resources": [
{
"resources": ["*"],
"matches": ["<all_urls>"]
}
]
"128": "ProfStatsUTDIcon128.png"
}
}

9 changes: 5 additions & 4 deletions extension/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function App() {
const [loading, setLoading] = useState(false);
const [rateMyProfessorRating, setRateMyProfessorRating] = useState(null);
const [gradeDistribution, setGradeDistribution] = useState([]);
const [options, setOptions] = useState(['test', 'test2', 'test3']);

const showToast = (status, description) => {
toast({
Expand All @@ -46,7 +47,7 @@ function App() {
setLoading(true);

try {
const ratingsResponse = await axios.get(`${API_URL}/ratings?teacher=${teacherName}`);
const ratingsResponse = await axios.get(`${API_URL}/ratings?teacher=${teacherName}&course=${course}`);
setRateMyProfessorRating(ratingsResponse.data);

try {
Expand Down Expand Up @@ -99,7 +100,7 @@ function App() {
<Stack spacing={2} width={300} align="center">
<Input
required
placeholder="Enter Teacher Name ex. Jey Veerasamy"
placeholder="Enter Teacher Name ex. Jason Smith"
value={teacherName}
onChange={(e) => setTeacherName(e.target.value)}
/>
Expand All @@ -121,11 +122,11 @@ function App() {
</Text>
<Text fontSize="xl">{rateMyProfessorRating.department}</Text>
<HStack width={300}>
{renderRateMyProfessorRating('Rating', rateMyProfessorRating.rating)}
{renderRateMyProfessorRating('Quality', rateMyProfessorRating.rating)}
<Spacer />
{renderRateMyProfessorRating('Difficulty', rateMyProfessorRating.difficulty)}
<Spacer />
{renderRateMyProfessorRating('Enjoyment?', rateMyProfessorRating.would_take_again)}
{renderRateMyProfessorRating('Enjoyment', rateMyProfessorRating.would_take_again)}
</HStack>
{chartData.length > 0 && (
<BarChart width={300} height={150} data={chartData}>
Expand Down
39 changes: 8 additions & 31 deletions server/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ProfStatsUTD - Backend
# ProfStatsUTD Backend

ProfStatsUTD is a Python Flask backend for the ProfStatsUTD project, providing information about professors and course grades at The University of Texas at Dallas.
This is the backend code for ProfStatsUTD, a Chrome extension that provides aggregated grades and professor ratings for courses at The University of Texas at Dallas (UTD).

## Database

Expand All @@ -13,27 +13,10 @@ npm run dev # Create the SQLite database from raw data and launch the Next.js

The SQLite database will be created in the `db` directory.

## Usage

1. Clone the repository:

```bash
git clone https://github.com/GiridharRNair/ProfStatsUTD.git
```

2. Install dependencies:

```bash
pip install -r requirements.txt
```

3. Run the Flask application:

```bash
python main.py
```

The application will run on `http://127.0.0.1:5000/` by default.
## Setup
1. Clone the repository: `git clone https://github.com/GiridharRNair/ProfStatsUTD`
2. Install dependencies: `pip install -r requirements.txt`
3. Run the backend: `python main.py`

## Endpoints

Expand All @@ -55,17 +38,11 @@ curl -X GET "http://127.0.0.1:5000/grades?teacher=Jey%20Veerasamy&course=CS1337"
- **Method:** `GET`
- **Parameters:**
- `teacher` (required): The name of the professor (Example: Jey Veerasamy).
- `course` (optional): The course in the format "CS1337" or "CS 1337".

#### Example

```bash
curl -X GET "http://127.0.0.1:5000/ratings?teacher=Jey%20Veerasamy"
curl -X GET "http://127.0.0.1:5000/ratings?teacher=Jey%20Veerasamy&course=CS1337"
```

## Error Handling

The backend includes error handlers for common HTTP exceptions, rendering corresponding HTML templates for 401, 403, 404, and 408 status codes.

## Acknowledgment

We would like to thank the developers of the [RateMyProfessorAPI](https://github.com/Nobelz/RateMyProfessorAPI) Python package.
5 changes: 5 additions & 0 deletions server/json/header.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"Authorization": "Basic dGVzdDp0ZXN0",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
"Content-Type": "application/json"
}
4 changes: 4 additions & 0 deletions server/json/professorquery.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"query":"query RatingsListQuery($id: ID!) {node(id: $id) {... on Teacher {school {id} courseCodes {courseName courseCount} firstName lastName numRatings avgDifficulty avgRating department wouldTakeAgainPercent}}}",
"variables": {}
}
4 changes: 4 additions & 0 deletions server/json/ratingsquery.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"query":"query RatingsListQuery($count: Int! $id: ID! $courseFilter: String $cursor: String) {node(id: $id) {... on Teacher {ratings(first: $count, after: $cursor, courseFilter: $courseFilter) {edges {node {comment date class helpfulRating isForOnlineClass helpfulRating difficultyRating attendanceMandatory wouldTakeAgain grade isForOnlineClass isForCredit ratingTags comment thumbsUpTotal thumbsDownTotal}}}}}}",
"variables": {}
}
65 changes: 43 additions & 22 deletions server/main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from werkzeug.exceptions import Forbidden, HTTPException, NotFound, RequestTimeout, Unauthorized
from flask import Flask, request, jsonify, render_template
from collections import OrderedDict
from professor import Professor
from flask_cors import CORS
import ratemyprofessor
import sqlite3
import os

Expand All @@ -16,6 +16,14 @@


def run_sql_query(subject, course_section=None, instructor=None):
"""
Run an SQL query on the SQLite database and aggregate the results.
:param subject: Subject code for the course.
:param course_section: Course section number.
:param instructor: Instructor's name.
:return: Aggregated data from the database.
"""
with sqlite3.connect(db_path) as conn:
modified_instructor = instructor.replace(" ", "% %")

Expand Down Expand Up @@ -57,6 +65,11 @@ def run_sql_query(subject, course_section=None, instructor=None):

@app.route('/grades', methods=['GET'])
def get_grades():
"""
Endpoint to retrieve aggregated grades data based on parameters.
:return: JSON response with aggregated data.
"""
try:
teacher_param = request.args.get('teacher')
course_param = request.args.get('course')
Expand All @@ -83,33 +96,41 @@ def get_grades():

@app.route('/ratings', methods=['GET'])
def get_ratings():
"""
Endpoint to retrieve professor ratings data based on parameters.
:return: JSON response with professor ratings data.
"""
try:
teacher_param = request.args.get('teacher')
course_param = request.args.get('course')

if not teacher_param:
return jsonify({"error": "Required parameter missing"}), 422
return jsonify({"error": "Required parameter 'teacher' missing"}), 422

professor = ratemyprofessor.get_professor_by_school_and_name(
ratemyprofessor.get_school_by_name("The University of Texas at Dallas"),
teacher_param.strip()
)

result_data = {}

if professor:
result_data = {
'id': professor.id,
'name': professor.name,
'department': professor.department,
'rating': professor.rating,
'difficulty': professor.difficulty,
'would_take_again': round(professor.would_take_again, 1) if professor.would_take_again is not None else None,
}

if result_data:
return jsonify(result_data), 200
professor = Professor(teacher_param.strip())

if course_param:
ratings = professor.get_ratings(course_param.strip().replace(" ", "").upper())
total_ratings = len(ratings)
total_rating = sum(rating.rating for rating in ratings)
total_difficulty = sum(rating.difficulty for rating in ratings)
professor_rating = round(total_rating / total_ratings, 1)
professor_difficulty = round(total_difficulty / total_ratings, 1)
else:
return jsonify({"error": "No data! Make sure you have the correct teacher name"}), 404
professor_rating = professor.rating
professor_difficulty = professor.difficulty

result_data = {
'id': professor.id,
'name': professor.name,
'department': professor.department,
'rating': professor_rating,
'difficulty': professor_difficulty,
'would_take_again': round(professor.would_take_again, 1) if professor.would_take_again is not None else None,
}

return jsonify(result_data), 200

except Exception as e:
return jsonify({"error": str(e)}), 400
Expand Down
Loading

0 comments on commit 8d20b5c

Please sign in to comment.