Files
Tomas Dvorak d27cf14110 first test
2026-02-08 14:14:55 +01:00

330 lines
9.6 KiB
Go

package handlers
import (
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"github.com/trackeep/backend/models"
)
type CalendarHandler struct {
db *gorm.DB
}
func NewCalendarHandler(db *gorm.DB) *CalendarHandler {
return &CalendarHandler{db: db}
}
// CalendarEventRequest represents the request body for creating/updating events
type CalendarEventRequest struct {
Title string `json:"title" binding:"required"`
Description string `json:"description"`
StartTime time.Time `json:"start_time" binding:"required"`
EndTime time.Time `json:"end_time" binding:"required"`
Type string `json:"type"`
Priority string `json:"priority"`
Location string `json:"location"`
Attendees string `json:"attendees"`
Recurring bool `json:"recurring"`
Rrule string `json:"rrule"`
Source string `json:"source"`
TaskID *uint `json:"task_id"`
BookmarkID *uint `json:"bookmark_id"`
NoteID *uint `json:"note_id"`
IsAllDay bool `json:"is_all_day"`
ReminderMinutes int `json:"reminder_minutes"`
}
// GetEvents retrieves calendar events for a user
func (h *CalendarHandler) GetEvents(c *gin.Context) {
userID := c.GetUint("userID")
// Parse query parameters
startStr := c.Query("start")
endStr := c.Query("end")
eventType := c.Query("type")
var events []models.CalendarEvent
query := h.db.Where("user_id = ?", userID)
// Filter by date range if provided
if startStr != "" && endStr != "" {
start, err := time.Parse(time.RFC3339, startStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid start date format"})
return
}
end, err := time.Parse(time.RFC3339, endStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid end date format"})
return
}
query = query.Where("start_time >= ? AND end_time <= ?", start, end)
}
// Filter by type if provided
if eventType != "" {
query = query.Where("type = ?", eventType)
}
if err := query.Preload("Task").Preload("Bookmark").Preload("Note").Find(&events).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch events"})
return
}
c.JSON(http.StatusOK, gin.H{"events": events})
}
// GetEvent retrieves a single calendar event
func (h *CalendarHandler) GetEvent(c *gin.Context) {
userID := c.GetUint("userID")
eventID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid event ID"})
return
}
var event models.CalendarEvent
if err := h.db.Where("id = ? AND user_id = ?", eventID, userID).
Preload("Task").Preload("Bookmark").Preload("Note").
First(&event).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "Event not found"})
} else {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch event"})
}
return
}
c.JSON(http.StatusOK, gin.H{"event": event})
}
// CreateEvent creates a new calendar event
func (h *CalendarHandler) CreateEvent(c *gin.Context) {
userID := c.GetUint("userID")
var req CalendarEventRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Validate time range
if req.EndTime.Before(req.StartTime) {
c.JSON(http.StatusBadRequest, gin.H{"error": "End time must be after start time"})
return
}
// Set default values
if req.Type == "" {
req.Type = "reminder"
}
if req.Priority == "" {
req.Priority = "medium"
}
if req.Source == "" {
req.Source = "trackeep"
}
event := models.CalendarEvent{
UserID: userID,
Title: req.Title,
Description: req.Description,
StartTime: req.StartTime,
EndTime: req.EndTime,
Type: req.Type,
Priority: req.Priority,
Location: req.Location,
Attendees: req.Attendees,
Recurring: req.Recurring,
Rrule: req.Rrule,
Source: req.Source,
TaskID: req.TaskID,
BookmarkID: req.BookmarkID,
NoteID: req.NoteID,
IsAllDay: req.IsAllDay,
ReminderMinutes: req.ReminderMinutes,
}
if err := h.db.Create(&event).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create event"})
return
}
c.JSON(http.StatusCreated, gin.H{"event": event})
}
// UpdateEvent updates an existing calendar event
func (h *CalendarHandler) UpdateEvent(c *gin.Context) {
userID := c.GetUint("userID")
eventID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid event ID"})
return
}
var event models.CalendarEvent
if err := h.db.Where("id = ? AND user_id = ?", eventID, userID).First(&event).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "Event not found"})
} else {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch event"})
}
return
}
var req CalendarEventRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Validate time range
if req.EndTime.Before(req.StartTime) {
c.JSON(http.StatusBadRequest, gin.H{"error": "End time must be after start time"})
return
}
// Update event fields
event.Title = req.Title
event.Description = req.Description
event.StartTime = req.StartTime
event.EndTime = req.EndTime
event.Type = req.Type
event.Priority = req.Priority
event.Location = req.Location
event.Attendees = req.Attendees
event.Recurring = req.Recurring
event.Rrule = req.Rrule
event.Source = req.Source
event.TaskID = req.TaskID
event.BookmarkID = req.BookmarkID
event.NoteID = req.NoteID
event.IsAllDay = req.IsAllDay
event.ReminderMinutes = req.ReminderMinutes
if err := h.db.Save(&event).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update event"})
return
}
c.JSON(http.StatusOK, gin.H{"event": event})
}
// DeleteEvent deletes a calendar event
func (h *CalendarHandler) DeleteEvent(c *gin.Context) {
userID := c.GetUint("userID")
eventID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid event ID"})
return
}
var event models.CalendarEvent
if err := h.db.Where("id = ? AND user_id = ?", eventID, userID).First(&event).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "Event not found"})
} else {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch event"})
}
return
}
if err := h.db.Delete(&event).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete event"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Event deleted successfully"})
}
// GetUpcomingEvents retrieves events for the next 7 days
func (h *CalendarHandler) GetUpcomingEvents(c *gin.Context) {
userID := c.GetUint("userID")
now := time.Now()
weekLater := now.AddDate(0, 0, 7)
var events []models.CalendarEvent
if err := h.db.Where("user_id = ? AND start_time >= ? AND start_time <= ?", userID, now, weekLater).
Order("start_time ASC").
Preload("Task").Preload("Bookmark").Preload("Note").
Find(&events).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch upcoming events"})
return
}
c.JSON(http.StatusOK, gin.H{"events": events})
}
// GetTodayEvents retrieves events for today
func (h *CalendarHandler) GetTodayEvents(c *gin.Context) {
userID := c.GetUint("userID")
now := time.Now()
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
endOfDay := startOfDay.Add(24 * time.Hour)
var events []models.CalendarEvent
if err := h.db.Where("user_id = ? AND start_time >= ? AND start_time < ?", userID, startOfDay, endOfDay).
Order("start_time ASC").
Preload("Task").Preload("Bookmark").Preload("Note").
Find(&events).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch today's events"})
return
}
c.JSON(http.StatusOK, gin.H{"events": events})
}
// GetDeadlines retrieves upcoming deadlines
func (h *CalendarHandler) GetDeadlines(c *gin.Context) {
userID := c.GetUint("userID")
now := time.Now()
monthLater := now.AddDate(0, 1, 0)
var events []models.CalendarEvent
if err := h.db.Where("user_id = ? AND type = ? AND start_time >= ? AND start_time <= ?", userID, "deadline", now, monthLater).
Order("start_time ASC").
Preload("Task").
Find(&events).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch deadlines"})
return
}
c.JSON(http.StatusOK, gin.H{"deadlines": events})
}
// ToggleEventCompletion toggles the completion status of an event
func (h *CalendarHandler) ToggleEventCompletion(c *gin.Context) {
userID := c.GetUint("userID")
eventID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid event ID"})
return
}
var event models.CalendarEvent
if err := h.db.Where("id = ? AND user_id = ?", eventID, userID).First(&event).Error; err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "Event not found"})
} else {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch event"})
}
return
}
event.IsCompleted = !event.IsCompleted
if err := h.db.Save(&event).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update event"})
return
}
c.JSON(http.StatusOK, gin.H{"event": event})
}