Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ RUN go build -o bin/vitty
FROM alpine:3.15 AS runner

WORKDIR /usr/src/app
RUN mkdir ./data

COPY --from=builder /usr/src/app/bin/vitty ./bin/vitty

Expand Down
43 changes: 32 additions & 11 deletions vitty-backend-api/admin/pkg/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import (
"net/http"
"reflect"

"github.com/GDGVIT/vitty-backend/vitty-backend-api/api/middleware"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/cli/commands"
"github.com/gofiber/fiber/v2"
"github.com/labstack/echo/v4"
"github.com/urfave/cli/v2"
)

type TemplateRenderer struct {
Expand All @@ -22,17 +26,20 @@ func (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c
return t.templates.ExecuteTemplate(w, name, data)
}

func AdminHandler(app *echo.Echo) {
group := app.Group("")
group.Use(JWTMiddleware)
group.GET("", GetModelsView)
group.GET("/:model", GetModelView)
group.GET("/:model/create", CreateItemView)
group.POST("/:model/create", CreateItem)
group.GET("/:model/:id", GetItemView)
group.GET("/:model/:id/edit", UpdateItemView)
group.PUT("/:model/:id", UpdateItem)
group.DELETE("/:model/:id", DeleteItem)
func AdminHandler(app fiber.Router) {
group := app.Group("/admin")
group.Use(middleware.JWTAuthMiddleware)
group.Use(middleware.IsAdminMiddleware)
group.Post("/empty-classrooms/seed", seedEmptyClassrooms)

// group.Get("", GetModelsView)
// group.Get("/:model", GetModelView)
// group.Get("/:model/create", CreateItemView)
// group.Post("/:model/create", CreateItem)
// group.Get("/:model/:id", GetItemView)
// group.Get("/:model/:id/edit", UpdateItemView)
// group.Put("/:model/:id", UpdateItem)
// group.Delete("/:model/:id", DeleteItem)
}

func GetModelsView(c echo.Context) error {
Expand Down Expand Up @@ -212,4 +219,18 @@ func DeleteItem(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]interface{}{
"message": "Item deleted",
})

}

func seedEmptyClassrooms(c *fiber.Ctx) error {
err := commands.GenerateEmptyRooms(&cli.Context{})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "classrooms seed failed",
})
}

return c.Status(fiber.StatusOK).JSON(fiber.Map{
"message": "classrooms has been initialized",
})
}
2 changes: 1 addition & 1 deletion vitty-backend-api/admin/pkg/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (s *AdminSvc) init() {
"message": "Hello World",
})
})
AdminHandler(s.WebApp)
// AdminHandler(s.WebApp)
}

func (s *AdminSvc) Register(model ModelInterface) {
Expand Down
2 changes: 2 additions & 0 deletions vitty-backend-api/api/v2/initialize.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v2

import (
"github.com/GDGVIT/vitty-backend/vitty-backend-api/admin/pkg"
"github.com/gofiber/fiber/v2"
)

Expand All @@ -13,4 +14,5 @@ func V2Handler(api fiber.Router) {
circleHandler(group)
reminderHandler(group)
noteHandler(group)
pkg.AdminHandler(group)
}
46 changes: 46 additions & 0 deletions vitty-backend-api/api/v2/userHandler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package v2

import (
"encoding/json"
"errors"
"fmt"
"log"
"os"
"strings"
"errors"
"fmt"
"log"
Expand All @@ -20,6 +26,7 @@ func userHandler(api fiber.Router) {
group.Get("/", getUsers)
group.Get("/search", searchUsers)
group.Get("/suggested", getSuggestedUsers)
group.Get("/emptyClassRooms", getEmptyClassRooms)
group.Get("/:username", getUser)
group.Delete("/:username", deleteUser)
}
Expand Down Expand Up @@ -105,3 +112,42 @@ func deleteUser(c *fiber.Ctx) error {
"detail": "User deleted successfully",
})
}

func getEmptyClassRooms(c *fiber.Ctx) error {
filterSlot := strings.ToUpper(c.Query("slot"))

if filterSlot == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"detail": "please mention the slot",
})
}

file, err := os.Open("./data/freeClasses.json")
if err != nil {
log.Printf("Error opening file: %v", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "please contact vitty support",
})
}
defer file.Close()

var freeClasses map[string]interface{}
decoder := json.NewDecoder(file)
err = decoder.Decode(&freeClasses)
if err != nil {
log.Fatalf("Error decoding JSON: %v", err)
}
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.ErrInternalServerError)
}

response := freeClasses[filterSlot]

if response == nil {
response = ""
}

return c.Status(fiber.StatusOK).JSON(map[string]interface{}{
filterSlot: response,
})
}
91 changes: 90 additions & 1 deletion vitty-backend-api/cli/commands/timetableCommands.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package commands

import (
"encoding/json"
"fmt"
"os"

"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/database"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/models"
Expand All @@ -22,6 +24,12 @@ var TimetableCommands = []*cli.Command{
Usage: "Fix slot times",
Action: fixSlotTimes,
},
{
Name: "empty-rooms",
Aliases: []string{"er"},
Usage: "Generates empty classrooms file",
Action: GenerateEmptyRooms,
},
{

Name: "seed-course-table",
Expand All @@ -44,7 +52,7 @@ func parseTimetable(c *cli.Context) error {

fmt.Println("Parsed data: ")
fmt.Println(timetableV1)
fmt.Println("\n\n")
fmt.Print("\n\n")

var timetableSlots []models.Slot
for _, slot := range timetableV1 {
Expand Down Expand Up @@ -81,6 +89,87 @@ func fixSlotTimes(c *cli.Context) error {
return nil
}

func GenerateEmptyRooms(c *cli.Context) error {
reset := "\033[0m"
red := "\033[31m"
green := "\033[32m"
cyan := "\033[36m "

fmt.Print(cyan, "Initiating ", reset)
fmt.Print("Extracting Class details... ")

err := database.DB.Exec(`
Drop table IF EXISTS joinData;
CREATE TABLE joinData (
class text,
slots JSONB
);

INSERT INTO joinData (class, slots)
SELECT
elems.data->>'venue' AS venue,
jsonb_agg( DISTINCT elems.data->>'slot') AS slots
FROM
timetables,
jsonb_array_elements(timetables.slots::jsonb) AS elems(data)
GROUP BY
elems.data->>'venue';
`).Error

if err != nil {
fmt.Println(red, "Failed")
fmt.Println("Error: ", err, reset)
}

fmt.Println(green, "Complete", reset)

fmt.Print(cyan, "Initiating ", reset)
fmt.Print("Looking for empty classes... ")

emptyClassRoomsJson := make(map[string]interface{})

for _, slot := range models.TimetableSlots {
freeClasses, err := findEmptyClassRooms(slot)

if err != nil {
fmt.Println(red, "Failed")
fmt.Printf("Slot %s was not able to be processed\nError: %s %s", slot, err, reset)
}

emptyClassRoomsJson[slot] = freeClasses
}

fmt.Println(green, "Complete", reset)
fmt.Print(cyan, "Initiating ", reset)
fmt.Print("Saving result... ")

jsonData, err := json.Marshal(emptyClassRoomsJson)
if err != nil {
fmt.Println("Error encoding JSON:", err)
}

err = database.DB.Exec(`
Drop table joindata;
`).Error

if err != nil {
fmt.Println(red, "Failed")
fmt.Println("Error: ", err, reset)
}

err = os.WriteFile("./data/freeClasses.json", jsonData, 0644)

if err != nil {
fmt.Println(red, "Failed")
fmt.Println("Error: ", err, reset)
return err
}

fmt.Println(green, "Complete", reset)

return nil
}

func seedCourseTable(c *cli.Context) error {
reset := "\033[0m"
red := "\033[31m"
Expand Down
42 changes: 42 additions & 0 deletions vitty-backend-api/cli/commands/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package commands

import (
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/database"
)

func findEmptyClassRooms(slot string) ([]string, error) {
var freeClasses []string
total := 0
offset := 0
limit := 1000

query := database.DB.
Table("joindata").
Where("NOT (slots @> '[\"?\"]')", database.DB.Raw(slot)).
Where("slots::text !~ '\\[\"L.*\"\\]'")

err := query.
Select("COUNT(class)").
Scan(&total).Error

if err != nil {
return freeClasses, err
}

for total >= 0 {
err := query.
Select("class").
Limit(limit).
Offset(offset).
Find(&freeClasses).Error

if err != nil {
return freeClasses, err
}

total -= limit
offset += limit
}

return freeClasses, nil
}
1 change: 1 addition & 0 deletions vitty-backend-api/internal/database/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func Connect(debug string, dbUrls string) {
})
} else {
DB, err = gorm.Open(postgres.Open(dbUrls), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
TranslateError: true,
})
}
Expand Down
4 changes: 4 additions & 0 deletions vitty-backend-api/internal/models/slots.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package models

var TimetableSlots = []string{"A1", "A2", "B1", "B2", "C1", "C2", "D1", "D2", "E1", "E2", "F1", "F2", "G1", "G2",
"TA1", "TA2", "TAA1", "TAA2", "TB1", "TB2", "TBB2", "TC1", "TC2", "TCC1", "TCC2", "TD1", "TD2", "TDD2", "TE1", "TE2", "TF1", "TF2",
"TG1", "TG2", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8", "V9", "V10", "V11", "W21", "W22", "X11", "X12", "X21", "Y11", "Y12", "Y21", "Z21"}

var DailySlots = map[string]map[string][]string{
"Monday": {
"Theory": {"A1", "F1", "D1", "TB1", "TG1", "A2", "F2", "D2", "TB2", "TG2", "V3"},
Expand Down
Loading