Skip to content

Commit

Permalink
Merge pull request #5 from GiridharRNair/Dev
Browse files Browse the repository at this point in the history
Version 1.0.8
  • Loading branch information
GiridharRNair authored Jan 9, 2024
2 parents 9a269f9 + e3da4da commit b5604d1
Show file tree
Hide file tree
Showing 40 changed files with 462 additions and 531 deletions.
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"printWidth": 150,
"printWidth": 160,
"tabWidth": 4,
"semi": true
}
75 changes: 34 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ ProfStats is a handy Chrome extension that puts professor ratings and grade dist

[![Vite](https://img.shields.io/badge/Powered_by-Vite-646CFF?style=for-the-badge&logo=vite)](https://vitejs.dev/)

[![React](https://img.shields.io/badge/Powered_by-React-61DAFB?style=for-the-badge&logo=react)](https://reactjs.org/)

[![Azure](https://img.shields.io/badge/Hosted_on-Azure-0089D6?style=for-the-badge&logo=microsoft-azure)](https://azure.microsoft.com/en-us/)

[![SQLite](https://img.shields.io/badge/Database-SQLite-003B57?style=for-the-badge&logo=sqlite)](https://www.sqlite.org/index.html)
Expand All @@ -25,59 +27,50 @@ ProfStats is a handy Chrome extension that puts professor ratings and grade dist

## Frontend Overview

Built with Vite with React, incorporating Chakra UI for the interface. It optimizes backend performance through debouncing, ensures data accuracy with client-side validation, and employs the [CRXJS](https://crxjs.dev/vite-plugin/) plugin for Chrome extension hot module reloading (HMR) during development.
Built with Vite, React, and Chakra UI for a streamlined interface. Optimizes backend performance through debouncing, ensures data accuracy with client-side validation, and utilizes [CRXJS](https://crxjs.dev/vite-plugin/) for Chrome extension hot module reloading (HMR) during development.

### Updating Version

Simply update the version in the `package.json` file, and when you start the server in development or production, it will automatically reflect the updated version in the manifest file. You might need to reload or remove and re-add the extension to see the updated version.
Simply update the version in `package.json`. Starting the server in development or production will automatically reflect the updated version in the manifest file. Reload or remove and re-add the extension to see the changes.

### Deployment

GitHub Actions automate the staging of the extension on the Chrome Web Store using [Chrome-Webstore-Upload-Action](https://github.com/fregante/chrome-webstore-upload). However, the user still needs to manually submit it for review, although the entire tedious uploading process is automated.
GitHub Actions automate staging on the Chrome Web Store using [Chrome-Webstore-Upload-Action](https://github.com/fregante/chrome-webstore-upload). While manual submission for review is required, the tedious uploading process is fully automated.

## Backend Overview

Developed in Golang using Gin Gonic, it utilizes an SQLite database generated by a Python script in `db_setup` based on grades data in `raw_data`. The system fetches ratings from the Rate My Professor GraphQL API and queries the aggregated grade distribution from the generated SQLite database for all courses or a specific course.
Built with Golang and Gin Gonic, the backend utilizes an SQLite database generated by a Python script in `db_setup`, sourcing data from `raw_data`. The system fetches ratings from the Rate My Professor GraphQL API and queries the aggregated grade distribution from the SQLite database for all courses or a specific course.

### Endpoints

#### 1. Get Professor Information

#### Endpoint: `/professor_info`

- **Method:** GET
- **Query Parameters:**
- `teacher` (required): Name of the professor.
- `course` (optional): Course subject and number (e.g. CS 1337).

#### Response

Returns detailed information about the specified professor, including ratings, department, and the grade distribution for all courses or a specific course.

#### 2. Get Course Information

#### Endpoint: `/course_info`

- **Method:** GET
- **Query Parameters:**
- `course` (required): Course subject and number (e.g. CS 1337).

#### Response

Returns the name and grade distribution of the specified course.

#### 3. Search Query Suggestions

#### Endpoint: `/suggestions`

- **Method:** GET
- **Query Parameters:**
- `teacher` (optional): Name of the professor.
- `course` (optional): Course subject and number (e.g. CS 1337).

#### Response

Returns a list of distinct professor and course names that are most similar to the specified query.
1. **Get Professor Information**

- **Endpoint:** `/professor_info`
- **Method:** GET
- **Query Parameters:**
- `teacher` (required): Name of the professor.
- `course` (optional): Course subject and number (e.g., CS 1337).
- **Response:**
- Detailed information about the specified professor, including ratings, department, and grade distribution for all courses or a specific course.

2. **Get Course Information**

- **Endpoint:** `/course_info`
- **Method:** GET
- **Query Parameters:**
- `course` (required): Course subject and number (e.g., CS 1337).
- **Response:**
- Returns the name and grade distribution of the specified course.

3. **Search Query Suggestions**

- **Endpoint:** `/suggestions`
- **Method:** GET
- **Query Parameters:**
- `teacher` (optional): Name of the professor.
- `course` (optional): Course subject and number (e.g., CS 1337).
- **Response:**
- Returns a list of distinct professor and course names similar to the specified query.

### CORS Configuration

Expand Down
11 changes: 7 additions & 4 deletions api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ FROM golang:1.21.4
# Set the working directory inside the container
WORKDIR /app

# Copy only the necessary files to the container's workspace
COPY . .
# Copy go mod and sum files
COPY go.mod go.sum ./

# Download and install any required dependencies
RUN go mod download

# Copy the rest of the application code
COPY . .

# Build the Go application
RUN go build -o main ./cmd/profstats
RUN go build -o main

# Set Gin to production mode
ENV GIN_MODE=release
Expand All @@ -20,4 +23,4 @@ ENV GIN_MODE=release
EXPOSE 80

# Run the application
CMD ["./main"]
CMD ["./main"]
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package handlers
package controllers

import (
"net/http"

"github.com/GiridharRNair/ProfStats-GinAPI/database"
"github.com/GiridharRNair/ProfStats-GinAPI/internal/course"
"github.com/GiridharRNair/ProfStats-GinAPI/course"
"github.com/GiridharRNair/ProfStats-GinAPI/db"
"github.com/gin-gonic/gin"
)

Expand All @@ -22,11 +22,17 @@ func GetCourseInformation(c *gin.Context) {
return
}

courseName, err := course.GetCourseName(subject, courseNumber)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
return
}

resultData := gin.H{
"subject": subject,
"course_number": courseNumber,
"course_name": course.GetCourseName(subject, courseNumber),
"grades": database.GetAggregatedGrades("", subject, courseNumber),
"course_name": courseName,
"grades": db.GetAggregatedGrades("", "", subject, courseNumber),
}

c.JSON(http.StatusOK, resultData)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package handlers
package controllers

import (
"net/http"
"strings"

"github.com/GiridharRNair/ProfStats-GinAPI/database"
"github.com/GiridharRNair/ProfStats-GinAPI/internal/professor"
"github.com/GiridharRNair/ProfStats-GinAPI/db"
"github.com/GiridharRNair/ProfStats-GinAPI/professor"
"github.com/gin-gonic/gin"
)

Expand Down Expand Up @@ -34,7 +34,7 @@ func GetProfessorInformation(c *gin.Context) {
"id": professor.ID,
"name": professor.Name,
"department": professor.Department,
"grades": database.GetAggregatedGrades(professor.Name, subject, courseNumber),
"grades": db.GetAggregatedGrades(teacher, professor.Name, subject, courseNumber),
"subject": subject,
"course_number": courseNumber,
"rating": professor.Rating,
Expand Down
35 changes: 35 additions & 0 deletions api/controllers/search_suggestions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package controllers

import (
"net/http"

"github.com/GiridharRNair/ProfStats-GinAPI/db"
"github.com/gin-gonic/gin"
)

func SuggestionsSearchQuery(c *gin.Context) {
teacher := c.Query("teacher")
course := c.Query("course")

defaultSuggestions := make(map[string][]string)

professorSuggestions, err := db.GetProfessorSuggestions(teacher)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
return
}

defaultSuggestions["professors"] = professorSuggestions

subject, courseNumber, _ := isValidCourseName(course)

courseSuggestions, err := db.GetCourseSuggestions(teacher, subject, courseNumber)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
return
}

defaultSuggestions["courses"] = courseSuggestions

c.JSON(http.StatusOK, defaultSuggestions)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package handlers
package controllers

import (
"regexp"
Expand All @@ -11,11 +11,11 @@ func isValidCourseName(courseName string) (string, string, bool) {
}

formattedCourseName := strings.ToUpper(strings.ReplaceAll(courseName, " ", ""))

match := regexp.MustCompile(`([a-zA-Z]+)([0-9Vv]*)`).FindStringSubmatch(formattedCourseName)

if len(match) == 3 {
return match[1], match[2], true
}

return "", "", false
return "", formattedCourseName, false
}
19 changes: 10 additions & 9 deletions api/internal/course/course.go → api/course/course.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"regexp"
"strings"
"time"
"unicode"
)

Expand All @@ -16,34 +17,34 @@ func isGraduateCourse(courseNumber string) bool {
return false
}

func GetCourseName(subject, courseNumber string) string {
func GetCourseName(subject, courseNumber string) (string, error) {
isGrad := isGraduateCourse(courseNumber)

urlFormat := "https://catalog.utdallas.edu/2023/%s/courses/%s"
urlFormat := "https://catalog.utdallas.edu/%d/%s/courses/%s"
urlType := "undergraduate"
if isGrad {
urlType = "graduate"
}

url := fmt.Sprintf(urlFormat, urlType, strings.ToLower(subject)+courseNumber)
url := fmt.Sprintf(urlFormat, time.Now().Year()-1, urlType, strings.ToLower(subject)+courseNumber)

resp, err := http.Get(url)
if err != nil {
return "Course name not found"
return "", err
}
defer resp.Body.Close()

bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "Course name not found"
return "", err
}

re := regexp.MustCompile(`<title>(.*?)\s*-\s*UT Dallas 2023 (Undergraduate|Graduate) Catalog - The University of Texas at Dallas</title>`)
match := re.FindStringSubmatch(string(bodyBytes[:1000]))
regexString := fmt.Sprintf(`<title>(.*?)\s*-\s*UT Dallas %d (Undergraduate|Graduate) Catalog - The University of Texas at Dallas</title>`, time.Now().Year()-1)
match := regexp.MustCompile(regexString).FindStringSubmatch(string(bodyBytes))

if len(match) > 1 {
return match[1]
return match[1], nil
}

return "Course name not found"
return "", fmt.Errorf("course not found in the %d catalog", time.Now().Year()-1)
}
34 changes: 0 additions & 34 deletions api/database/get_course_suggestions.go

This file was deleted.

Loading

0 comments on commit b5604d1

Please sign in to comment.