spin-backend/internal/httpapi/handlers_calendar.go
theorose49 995dd36167
All checks were successful
build-and-push / build (push) Successful in 32s
feat: 대시보드 내 이슈(/my/tasks) + 전체 캘린더(CalendarEvent) + 메일 AI 요약(OpenAI)
- GET /my/tasks: 전 프로젝트에서 나에게 배정된 작업 + projectName (대시보드 JIRA 보드용)
  · fix: ORDER BY "end"(예약어) 따옴표 처리
- CalendarEvent 모델 + /calendar/events CRUD(본인 소유), nav에 캘린더 추가
- internal/ai(OpenAI, stdlib): 메일 동기화 시 신규 메일에 한 줄 AI 요약 생성(OPENAI_API_KEY)
  · ProjectMailMsg.Summary, 회당 40건 상한
- nav inbox 라벨 쪽지함으로 통일

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:06:55 +09:00

66 lines
1.9 KiB
Go

package httpapi
import (
"net/http"
"spin/internal/models"
"github.com/go-chi/chi/v5"
)
// 개인 캘린더 — 각자 본인 이벤트만 보고 관리(분류: 프로젝트/기타/개인 + 색).
func (s *Server) handleListEvents(w http.ResponseWriter, r *http.Request) {
var out []models.CalendarEvent
s.db.Where("lower(owner_email) = lower(?)", s.email(r)).Order("start asc").Find(&out)
writeJSON(w, http.StatusOK, out)
}
func (s *Server) handleCreateEvent(w http.ResponseWriter, r *http.Request) {
var e models.CalendarEvent
if err := decodeJSON(r, &e); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
e.ID = ""
e.OwnerEmail = s.email(r)
s.db.Create(&e)
writeJSON(w, http.StatusCreated, e)
}
func (s *Server) handlePatchEvent(w http.ResponseWriter, r *http.Request) {
var e models.CalendarEvent
if err := s.db.First(&e, "id = ?", chi.URLParam(r, "eId")).Error; err != nil {
writeError(w, http.StatusNotFound, "일정을 찾을 수 없습니다")
return
}
if !s.owns(r, e.OwnerEmail) {
writeError(w, http.StatusForbidden, "본인 일정만 수정할 수 있습니다")
return
}
var patch map[string]interface{}
if err := decodeJSON(r, &patch); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
delete(patch, "id")
delete(patch, "ownerEmail")
s.db.Model(&e).Updates(snakeKeys(patch))
s.db.First(&e, "id = ?", e.ID)
writeJSON(w, http.StatusOK, e)
}
func (s *Server) handleDeleteEvent(w http.ResponseWriter, r *http.Request) {
var e models.CalendarEvent
if err := s.db.First(&e, "id = ?", chi.URLParam(r, "eId")).Error; err != nil {
writeError(w, http.StatusNotFound, "일정을 찾을 수 없습니다")
return
}
if !s.owns(r, e.OwnerEmail) {
writeError(w, http.StatusForbidden, "본인 일정만 삭제할 수 있습니다")
return
}
s.db.Delete(&models.CalendarEvent{}, "id = ?", e.ID)
writeJSON(w, http.StatusOK, map[string]bool{"ok": true})
}