Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reminders #47

Merged
merged 5 commits into from
Jan 6, 2025
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
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
}
1 change: 1 addition & 0 deletions vitty-backend-api/api/v2/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ func V2Handler(api fiber.Router) {
userHandler(group)
timetableHandler(group)
friendHandler(group)
reminderHandler(group)
noteHandler(group)
}
135 changes: 135 additions & 0 deletions vitty-backend-api/api/v2/reminderHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package v2

import (
"strings"

"github.com/GDGVIT/vitty-backend/vitty-backend-api/api/middleware"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/api/serializers"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/models"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/utils"
"github.com/gofiber/fiber/v2"
"github.com/labstack/gommon/log"
)

func reminderHandler(api fiber.Router) {
group := api.Group("/reminders")
group.Use(middleware.JWTAuthMiddleware)
group.Get("/", getReminders)
group.Post("/", createReminder)
group.Patch("/", updateReminder)
group.Delete("/:reminderId?", deleteReminder)
}

func getReminders(c *fiber.Ctx) error {
var reminder models.Reminders

username := c.Locals("user").(models.User).Username
reminder.UserName = username

err, reminders := reminder.GetReminders()
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"detail": "Reminders not fetched",
})
}

if len(reminders) == 0 {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"detail": "No reminders found",
})
}

return c.Status(fiber.StatusOK).JSON(fiber.Map{
"data": serializers.RemindersSerializer(reminders),
})
}

func createReminder(c *fiber.Ctx) error {
var reminder models.Reminders

if err := c.BodyParser(&reminder); err != nil {
log.Error(err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid request body ",
})
}

if reminder.ReminderName == nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Reminder name is required",
})
}

if reminder.ReminderContent == nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Reminder content is required",
})
}

if !strings.Contains(reminder.ReminderId, "rem_") || len(reminder.ReminderId) < 32 {
reminder.ReminderId = utils.UUIDWithPrefix("rem")
}

username := c.Locals("user").(models.User).Username
reminder.UserName = username
reminder.CreateReminder()

return c.Status(fiber.StatusOK).JSON(fiber.Map{
"detail": "Reminder Saved Successfully",
})
}

func updateReminder(c *fiber.Ctx) error {
var reminder models.Reminders

if err := c.BodyParser(&reminder); err != nil {
log.Error(err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid request body ",
})
}

if reminder.ReminderId == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"detail": "Reminder id is required",
})
}

err := reminder.UpdateReminder()
if err != nil {
log.Error(err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"detail": "Reminder not updated",
})
}

return c.Status(fiber.StatusOK).JSON(fiber.Map{
"detail": "Reminder Saved Successfully",
})
}

func deleteReminder(c *fiber.Ctx) error {
var reminder models.Reminders

reminderId := c.Params("reminderId")

if reminderId == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"detail": "Reminder id is missing",
})
}

reminder.ReminderId = reminderId
username := c.Locals("user").(models.User).Username
reminder.UserName = username

err := reminder.DeleteReminder()

if err != nil {
log.Info(err.Error())
return c.Status(fiber.StatusBadRequest).JSON(fiber.ErrBadRequest)
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"detail": "Reminder deleted successfully",
})
}
14 changes: 14 additions & 0 deletions vitty-backend-api/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
vittyCli "github.com/GDGVIT/vitty-backend/vitty-backend-api/cli"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/auth"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/database"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/jobs"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/models"
"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/utils"
"github.com/gofiber/fiber/v2"
"github.com/urfave/cli/v2"
)
Expand Down Expand Up @@ -37,6 +39,10 @@ type Env struct {
google_client_id string
google_client_secret string
google_redirect_uri string

// Job Variable
isRunJobs string
jobTime jobs.JobTime
}

// Method to create a new VittyApp
Expand All @@ -55,6 +61,11 @@ func (v *VittyApp) setEnv() {
v.env.google_client_id = os.Getenv("GOOGLE_CLIENT_ID")
v.env.google_client_secret = os.Getenv("GOOGLE_CLIENT_SECRET")
v.env.google_redirect_uri = os.Getenv("GOOGLE_REDIRECT_URI")

//Jobs
v.env.isRunJobs = os.Getenv("RUN_JOBS")
v.env.jobTime = utils.ParseJobTimes()

}

// Method to initialize CLI app
Expand Down Expand Up @@ -94,6 +105,9 @@ func (v *VittyApp) init() {
auth.InitializeGoogleOauth(v.env.google_client_id, v.env.google_client_secret, v.env.google_redirect_uri)
auth.InitializeFirebaseApp()

// Initialize jobs
jobs.InitializeJobs(v.env.isRunJobs, v.env.debug, v.env.jobTime)

// Initialize Web app
v.initWebApp()

Expand Down
11 changes: 10 additions & 1 deletion vitty-backend-api/example.env/example.local
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,13 @@ POSTGRES_PORT=5432
# Auth Variables
# ---------------------------------------------------------------
OAUTH_CALLBACK_URL=http://localhost:3000/auth/callback
JWT_SECRET=secret
JWT_SECRET=secret

# Job Variables
# ---------------------------------------------------------------
RUN_JOBS=false
#Works only if debug is true
DAILY_JOB_MIN=0
DAILY_JOB_SEC=10
WEEKLY_JOB_MIN=0
WEEKLY_JOB_SEC=20
4 changes: 3 additions & 1 deletion vitty-backend-api/example.env/example.production
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ POSTGRES_PORT=5432
# Auth Variables
# ---------------------------------------------------------------
OAUTH_CALLBACK_URL=https://<url>/auth/callback
JWT_SECRET=secret
JWT_SECRET=secret
# ---------------------------------------------------------------
RUN_JOBS=false
60 changes: 60 additions & 0 deletions vitty-backend-api/internal/jobs/jobs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package jobs

import (
"log"
"time"

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

type JobTime struct {
DAILY_JOB_MIN int
DAILY_JOB_SEC int
WEEKLY_JOB_MIN int
WEEKLY_JOB_SEC int
}

func InitializeJobs(isRunJobs string, debug string, jobTimes JobTime) {
if isRunJobs == "true" {
if debug == "true" {

timeDailyJob := time.Duration(jobTimes.DAILY_JOB_MIN)*time.Minute + time.Duration(jobTimes.DAILY_JOB_SEC)*time.Second
timeWeeklyJob := time.Duration(jobTimes.WEEKLY_JOB_MIN)*time.Minute + time.Duration(jobTimes.WEEKLY_JOB_SEC)*time.Second
go startDailyJob(timeDailyJob)
go startWeeklyJob(timeWeeklyJob)
} else {
go startDailyJob(24 * time.Hour)
go startWeeklyJob(7 * 24 * time.Hour)
}
log.Println("Jobs are running")
} else {
log.Println("Jobs disabled")
}

}

var reminder models.Reminders

func startDailyJob(jobTime time.Duration) {
ticker := time.NewTicker(jobTime)
defer ticker.Stop()

for {
select {
case <-ticker.C:
reminder.SoftDeleteExpiredReminders()
}
}
}

func startWeeklyJob(jobTime time.Duration) {
ticker := time.NewTicker(jobTime)
defer ticker.Stop()

for {
select {
case <-ticker.C:
reminder.CleanupOldReminders()
}
}
}
1 change: 1 addition & 0 deletions vitty-backend-api/internal/models/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ func InitializeModels() {
"User": &User{},
"Timetable": &Timetable{},
"Friend Requests": &FriendRequest{},
"Reminders": &Reminders{},
"Notes": &Notes{},
"Courses": &Courses{},
}
Expand Down
68 changes: 68 additions & 0 deletions vitty-backend-api/internal/models/reminders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package models

import (
"time"

"github.com/GDGVIT/vitty-backend/vitty-backend-api/internal/database"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
)

type Reminders struct {
ReminderId string `json:"reminder_id,omitempty" gorm:"unique"`
ReminderName *string `json:"reminder_name" gorm:"primaryKey"`
UserName string `json:"user_name" gorm:"primaryKey;foreignKey:Username;constraint:OnDelete:CASCADE"`
ReminderContent *string `json:"reminder_content"`
ReminderTime *time.Time `json:"reminder_time,omitempty"`
User User `gorm:"foreignKey:UserName;references:Username;constraint:OnDelete:CASCADE"`
DeletedAt soft_delete.DeletedAt `json:"-,omitempty" gorm:"index"`
}

func (r *Reminders) CreateReminder() error {
err := database.DB.Create(&r).Error
return err
}

func (r *Reminders) GetReminders() (error, []Reminders) {
var reminders []Reminders
err := database.DB.Where(&r).Find(&reminders).Error
return err, reminders
}

func (r *Reminders) UpdateReminder() error {
updateInteface := make(map[string]interface{})

if r.ReminderName != nil {
updateInteface["reminder_name"] = *r.ReminderName
}

if r.ReminderContent != nil {
updateInteface["reminder_content"] = *r.ReminderContent
}

if r.ReminderTime != nil {
updateInteface["reminder_time"] = *r.ReminderTime
}

err := database.DB.Model(&Reminders{}).Where("reminder_id = ?", r.ReminderId).UpdateColumns(updateInteface).Error

return err
}

func (r *Reminders) DeleteReminder() error {
result := database.DB.Where("reminder_id = ? AND username like ?", r.ReminderId, r.UserName).Delete(&r)
if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}

return result.Error
}

func (r *Reminders) SoftDeleteExpiredReminders() {
now := time.Now()
database.DB.Model(&Reminders{}).Where("reminder_time < ?", now).Delete(&Reminders{})
}

func (r *Reminders) CleanupOldReminders() {
database.DB.Unscoped().Where("deleted_at < NOW() - INTERVAL '7 days'").Delete(&Reminders{})
}
Loading
Loading