first commit

Made-with: Cursor
This commit is contained in:
Michilis
2026-02-28 02:17:55 +00:00
commit 41f6ae916f
92 changed files with 12332 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
package service
import (
"context"
"github.com/calendarapi/internal/models"
"github.com/calendarapi/internal/repository"
"github.com/calendarapi/internal/utils"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
type AttendeeService struct {
queries *repository.Queries
calendar *CalendarService
}
func NewAttendeeService(queries *repository.Queries, calendar *CalendarService) *AttendeeService {
return &AttendeeService{queries: queries, calendar: calendar}
}
func (s *AttendeeService) AddAttendees(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, attendees []AddAttendeeRequest) (*models.Event, error) {
ev, err := s.queries.GetEventByID(ctx, utils.ToPgUUID(eventID))
if err != nil {
if err == pgx.ErrNoRows {
return nil, models.ErrNotFound
}
return nil, models.ErrInternal
}
calID := utils.FromPgUUID(ev.CalendarID)
role, err := s.calendar.GetRole(ctx, calID, userID)
if err != nil {
return nil, err
}
if role != "owner" && role != "editor" {
return nil, models.ErrForbidden
}
for _, a := range attendees {
_, err := s.queries.CreateAttendee(ctx, repository.CreateAttendeeParams{
ID: utils.ToPgUUID(uuid.New()),
EventID: utils.ToPgUUID(eventID),
UserID: optionalPgUUID(a.UserID),
Email: utils.ToPgTextPtr(a.Email),
})
if err != nil {
return nil, models.ErrInternal
}
}
reminders, _ := loadRemindersHelper(ctx, s.queries, eventID)
atts, _ := loadAttendeesHelper(ctx, s.queries, eventID)
attachments, _ := loadAttachmentsHelper(ctx, s.queries, eventID)
return eventFromDB(ev, reminders, atts, attachments), nil
}
func (s *AttendeeService) UpdateStatus(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, attendeeID uuid.UUID, status string) (*models.Event, error) {
ev, err := s.queries.GetEventByID(ctx, utils.ToPgUUID(eventID))
if err != nil {
if err == pgx.ErrNoRows {
return nil, models.ErrNotFound
}
return nil, models.ErrInternal
}
calID := utils.FromPgUUID(ev.CalendarID)
role, err := s.calendar.GetRole(ctx, calID, userID)
if err != nil {
return nil, err
}
att, err := s.queries.GetAttendeeByID(ctx, utils.ToPgUUID(attendeeID))
if err != nil {
if err == pgx.ErrNoRows {
return nil, models.ErrNotFound
}
return nil, models.ErrInternal
}
isOrganizer := role == "owner" || role == "editor"
isOwnAttendee := att.UserID.Valid && utils.FromPgUUID(att.UserID) == userID
if !isOrganizer && !isOwnAttendee {
return nil, models.ErrForbidden
}
if status != "pending" && status != "accepted" && status != "declined" && status != "tentative" {
return nil, models.NewValidationError("status must be pending, accepted, declined, or tentative")
}
_, err = s.queries.UpdateAttendeeStatus(ctx, repository.UpdateAttendeeStatusParams{
ID: utils.ToPgUUID(attendeeID),
Status: status,
})
if err != nil {
return nil, models.ErrInternal
}
reminders, _ := loadRemindersHelper(ctx, s.queries, eventID)
atts, _ := loadAttendeesHelper(ctx, s.queries, eventID)
attachments, _ := loadAttachmentsHelper(ctx, s.queries, eventID)
return eventFromDB(ev, reminders, atts, attachments), nil
}
func (s *AttendeeService) DeleteAttendee(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, attendeeID uuid.UUID) error {
ev, err := s.queries.GetEventByID(ctx, utils.ToPgUUID(eventID))
if err != nil {
if err == pgx.ErrNoRows {
return models.ErrNotFound
}
return models.ErrInternal
}
calID := utils.FromPgUUID(ev.CalendarID)
role, err := s.calendar.GetRole(ctx, calID, userID)
if err != nil {
return err
}
if role != "owner" && role != "editor" {
return models.ErrForbidden
}
return s.queries.DeleteAttendee(ctx, repository.DeleteAttendeeParams{
ID: utils.ToPgUUID(attendeeID),
EventID: utils.ToPgUUID(eventID),
})
}
type AddAttendeeRequest struct {
UserID *uuid.UUID
Email *string
}