Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
05c8f87
fix: merged slot for lab while fetching timetable
TheSilentSage Jan 6, 2025
4d87c65
feat: added courses table
TheSilentSage Jan 6, 2025
e2c68e5
feat: users can save course-wise notes
TheSilentSage Jan 6, 2025
7f5f24b
feat: users can add reminders
TheSilentSage Jan 6, 2025
06a0320
feat: added option for users to hide timetable from friends
TheSilentSage Jan 6, 2025
e2f79b3
feat: users can form circles and find leisure timings
TheSilentSage Jan 6, 2025
c49ccd1
feat: empty classroom (#50)
TheSilentSage Jun 28, 2025
50a694a
fix: bug from last commit
dk-a-dev Jun 29, 2025
81b02df
feat: user deletion
dk-a-dev Jun 29, 2025
bcc6636
fix: parser regex improved to include new line and fixed logic to par…
dk-a-dev Jun 30, 2025
0953176
feat: join code for users to join without invitation (#52)
TheSilentSage Jun 30, 2025
78f6490
feat: included circle ID and join code in response for generated circ…
dk-a-dev Jul 5, 2025
b2a5b6f
feat: add campus field to user model and update campus
dk-a-dev Jul 5, 2025
7182b85
feat: enhance timetable detection with support for additional formats
dk-a-dev Jul 5, 2025
2769eb7
fix: bhopal campus support to timetable serialization and parsing logic
dk-a-dev Jul 13, 2025
515653f
fix: Chennai campus support with timetable parsing and slot management
dk-a-dev Jul 13, 2025
26a2d21
fix: parser logic for multiple campus
dk-a-dev Jul 15, 2025
1faae3b
fix: remove unused Bhopal slots in empty room generation and improve …
dk-a-dev Jul 17, 2025
a7addde
feat: add endpoint to retrieve a circle member's timetable
dk-a-dev Jul 17, 2025
9a595f4
feat: add join code generation to circle creation response
dk-a-dev Jul 17, 2025
29a8094
refactor: simplify JSON response in getCircleMemberTimetable function
dk-a-dev Jul 17, 2025
411b0e4
fix: update timetable slots to include empty slot and time and fixed …
dk-a-dev Jul 18, 2025
00a52c4
chore: api v2 to v3 migration
TheSilentSage Jul 18, 2025
d76db62
fix: overlapping route circle member timetable causes unexpected beh…
TheSilentSage Jul 18, 2025
f35ce95
chore: remove unused files (#54)
TheSilentSage Jul 18, 2025
b313c6e
feat: bulk send circle requests (#56)
TheSilentSage Jul 19, 2025
d0cc220
fix: url encoded circle name (#57)
TheSilentSage Jul 19, 2025
d038f6d
feat: get the list of active friends (#58)
TheSilentSage Jul 27, 2025
27fea4f
feat: friend active status list returns all results (#59)
TheSilentSage Aug 3, 2025
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
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ 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

COPY --from=builder /usr/src/app/credentials ./credentials
COPY --from=builder /usr/src/app/data ./data


RUN apk --no-cache add tzdata
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ vitty.bat cli <command>
<br>

## API Documentation
Postman API documentation - [Vitty API](https://documenter.getpostman.com/view/23405999/2s93zFWeZx)
Postman API documentation - [Vitty API](https://documenter.getpostman.com/view/29639924/2sAYJ7fJWD)

<br>
<br>
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/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

v1 "github.com/GDGVIT/vitty-backend/vitty-backend-api/api/v1"
v2 "github.com/GDGVIT/vitty-backend/vitty-backend-api/api/v2"
v3 "github.com/GDGVIT/vitty-backend/vitty-backend-api/api/v3"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
Expand Down Expand Up @@ -42,6 +43,7 @@ func NewWebApi() *fiber.App {
api := fiberApp.Group("/api")
v1.V1Handler(api)
v2.V2Handler(api)
v3.V3Handler(api)

return fiberApp
}
58 changes: 58 additions & 0 deletions vitty-backend-api/api/serializers/circles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package serializers

import "github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/models"

func CirclesListSerializer(ucj []models.UsersCirclesJoin) []map[string]interface{} {
var result []map[string]interface{}

for _, userCircle := range ucj {

out := map[string]interface{}{
"circle_id": userCircle.CID,
"circle_role": userCircle.CircleRole,
"circle_name": userCircle.Circles.CircleName,
"circle_join_code": userCircle.Circles.CircleJoinCode,
}

result = append(result, out)
}

return result

}

func CircleRequestsSerializer(circleRequests []models.CircleRequest) []map[string]interface{} {
var result []map[string]interface{}

for _, circleRequest := range circleRequests {
out := map[string]interface{}{
"from_username": circleRequest.FromUsername,
"to_username": circleRequest.ToUsername,
"circle_id": circleRequest.CID,
"circle_name": circleRequest.Circles.CircleName,
}
result = append(result, out)
}

return result
}

func UsersListCircleSerializer(users []models.User) []map[string]interface{} {
var result []map[string]interface{}

for _, user := range users {

currStatus := user.GetCurrentStatus()

out := map[string]interface{}{
"current_status": currStatus,
"username": user.Username,
"name": user.Name,
"picture": user.Picture,
"email": user.Email,
}
result = append(result, out)
}

return result
}
12 changes: 12 additions & 0 deletions vitty-backend-api/api/serializers/friends.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,15 @@ func FriendRequestsSerializer(friend_requests []models.FriendRequest, request_us
}
return friend_requests_list
}

func ActiveFriendsSerializer(userFriends *[]models.UserFriends) []map[string]interface{} {
var activeFriends []map[string]interface{}

for _, userFriend := range *userFriends {
activeFriends = append(activeFriends, map[string]interface{}{
"friend_username": userFriend.FriendUsername,
"hide": userFriend.Hide,
})
}
return activeFriends
}
19 changes: 19 additions & 0 deletions vitty-backend-api/api/serializers/notes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package serializers

import "github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/models"

func NotesSerializer(notes []models.Notes) []map[string]interface{} {
var result []map[string]interface{}

for _, note := range notes {
out := map[string]interface{}{
"note_id": note.NoteID,
"note_name": note.NoteName,
"note_content": note.NoteContent,
"course_id": note.CourseID,
"course_name": note.Courses.CourseName,
}
result = append(result, out)
}
return result
}
18 changes: 18 additions & 0 deletions vitty-backend-api/api/serializers/reminders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package serializers

import "github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/models"

func RemindersSerializer(reminders []models.Reminders) []map[string]interface{} {
var result []map[string]interface{}

for _, reminder := range reminders {
out := map[string]interface{}{
"reminder_id": reminder.ReminderId,
"reminder_name": reminder.ReminderName,
"reminder_content": reminder.ReminderContent,
"reminder_time": reminder.ReminderTime,
}
result = append(result, out)
}
return result
}
6 changes: 3 additions & 3 deletions vitty-backend-api/api/serializers/timetable.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package serializers

import "github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/models"

func TimetableSerializer(timetable models.Timetable) map[string]interface{} {
return map[string]interface{}{
"data": timetable.GetDaywiseTimetable(),
func TimetableSerializer(timetable models.Timetable, campus string) map[string]interface{} {
return map[string]any{
"data": timetable.GetDaywiseTimetable(campus),
}
}
9 changes: 8 additions & 1 deletion vitty-backend-api/api/serializers/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ func UserLoginSerializer(user models.User, token string) map[string]interface{}
"name": user.Name,
"picture": user.Picture,
"role": user.Role,
"campus": user.Campus,
"token": token,
}
}
Expand Down Expand Up @@ -44,12 +45,18 @@ func UserListSerializer(users []*models.User, request_user models.User) []map[st
}

func UserSerializer(user models.User, request_user models.User) map[string]interface{} {
campus := "vellore"
if user.Campus != nil {
campus = string(*user.Campus)
}

return map[string]interface{}{
"username": user.Username,
"name": user.Name,
"picture": user.Picture,
"email": user.Email,
"timetable": TimetableSerializer(user.GetTimeTable()),
"campus": user.Campus,
"timetable": TimetableSerializer(user.GetTimeTable(), campus),
"friend_status": request_user.CheckFriendStatus(user),
"friends_count": user.FriendsCount(),
"mutual_friends_count": request_user.CountMutualFriends(user),
Expand Down
2 changes: 1 addition & 1 deletion vitty-backend-api/api/v1/timetableHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func getTimetableV2(c *fiber.Ctx) error {
})
}

slots, err := utils.DetectTimetableV2(response.Data)
slots, err := utils.DetectTimetableV2(response.Data, "")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"detail": err.Error(),
Expand Down
39 changes: 32 additions & 7 deletions vitty-backend-api/api/v2/authHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"google.golang.org/api/idtoken"
)

func authHandler(api fiber.Router) {
func AuthHandler(api fiber.Router) {
group := api.Group("/auth")
group.Post("/check-username", checkUsernameValidity)
group.Post("/check-user-exists", checkUserExists)
Expand Down Expand Up @@ -69,9 +69,10 @@ func checkUserExists(c *fiber.Ctx) error {

func googleLogin(c *fiber.Ctx) error {
type RequestBody struct {
Id_token string `json:"id_token"`
RegNo string `json:"reg_no,omitempty"`
Username string `json:"username,omitempty"`
Id_token string `json:"id_token"`
RegNo string `json:"reg_no,omitempty"`
Username string `json:"username,omitempty"`
Campus *models.Campus `json:"campus,omitempty"`
}

var body RequestBody
Expand All @@ -82,6 +83,13 @@ func googleLogin(c *fiber.Ctx) error {
})
}

// Validate campus if provided
if body.Campus != nil && !body.Campus.Valid() {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"detail": "Invalid campus. Must be 'vellore' or 'chennai' or 'bhopal'",
})
}

idtoken, err := idtoken.Validate(context.Background(), body.Id_token, auth.OauthConf.ClientID)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
Expand All @@ -101,6 +109,10 @@ func googleLogin(c *fiber.Ctx) error {
if user.Picture != idtoken.Claims["picture"].(string) {
database.DB.Model(&user).Update("picture", idtoken.Claims["picture"].(string))
}
// Update campus if provided and different
if body.Campus != nil && user.Campus != body.Campus {
database.DB.Model(&user).Update("campus", body.Campus)
}
} else {

username := strings.ToLower(body.Username)
Expand All @@ -114,6 +126,7 @@ func googleLogin(c *fiber.Ctx) error {
user.Picture = idtoken.Claims["picture"].(string)
user.Username = username
user.RegNo = body.RegNo
user.Campus = body.Campus

err = database.DB.Create(&user).Error
if err != nil {
Expand All @@ -134,9 +147,10 @@ func googleLogin(c *fiber.Ctx) error {

func firebaseLogin(c *fiber.Ctx) error {
type RequestBody struct {
UUID string `json:"uuid"`
RegNo string `json:"reg_no,omitempty"`
Username string `json:"username,omitempty"`
UUID string `json:"uuid"`
RegNo string `json:"reg_no,omitempty"`
Username string `json:"username,omitempty"`
Campus *models.Campus `json:"campus,omitempty"`
}

var body RequestBody
Expand All @@ -147,6 +161,12 @@ func firebaseLogin(c *fiber.Ctx) error {
})
}

if body.Campus != nil && !body.Campus.Valid() {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"detail": "Invalid campus. Must be 'vellore' or 'chennai' or 'bhopal'",
})
}

client, err := auth.FirebaseApp.Auth(context.Background())
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
Expand All @@ -172,6 +192,10 @@ func firebaseLogin(c *fiber.Ctx) error {
if user.Picture != u_rec.ProviderUserInfo[0].PhotoURL {
database.DB.Model(&user).Update("picture", u_rec.ProviderUserInfo[0].PhotoURL)
}

if body.Campus != nil && user.Campus != body.Campus {
database.DB.Model(&user).Update("campus", body.Campus)
}
} else {

username := strings.ToLower(body.Username)
Expand All @@ -187,6 +211,7 @@ func firebaseLogin(c *fiber.Ctx) error {
user.Name = u_rec.ProviderUserInfo[0].DisplayName
user.Username = username
user.RegNo = body.RegNo
user.Campus = body.Campus
err = database.DB.Create(&user).Error
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
Expand Down
Loading
Loading