All checks were successful
build-and-push / build (push) Successful in 32s
- 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>
70 lines
3.0 KiB
Go
70 lines
3.0 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"spin/internal/models"
|
|
)
|
|
|
|
// MeResponse enriches the proxy identity with the matched Member profile.
|
|
type MeResponse struct {
|
|
User User `json:"user"`
|
|
Member *models.Member `json:"member"`
|
|
IsAdmin bool `json:"isAdmin"`
|
|
LogoutURL string `json:"logoutUrl"`
|
|
}
|
|
|
|
func (s *Server) handleMe(w http.ResponseWriter, r *http.Request) {
|
|
u := currentUser(r.Context())
|
|
writeJSON(w, http.StatusOK, MeResponse{
|
|
User: u,
|
|
Member: s.lookupMember(u.Email),
|
|
IsAdmin: s.isAdmin(r),
|
|
LogoutURL: s.cfg.LogoutURL,
|
|
})
|
|
}
|
|
|
|
// NavItem is one sidebar entry; adminOnly entries are filtered for members.
|
|
type NavItem struct {
|
|
Key string `json:"key"`
|
|
Label string `json:"label"`
|
|
Path string `json:"path"`
|
|
Icon string `json:"icon"`
|
|
AdminOnly bool `json:"adminOnly"`
|
|
Section string `json:"section"`
|
|
}
|
|
|
|
var navItems = []NavItem{
|
|
{Key: "dashboard", Label: "대시보드", Path: "/", Icon: "LayoutDashboard", Section: "개요"},
|
|
{Key: "inbox", Label: "쪽지함", Path: "/inbox", Icon: "Inbox", Section: "개요"},
|
|
{Key: "calendar", Label: "캘린더", Path: "/calendar", Icon: "CalendarDays", Section: "나의 업무"},
|
|
{Key: "attendance", Label: "근무", Path: "/attendance", Icon: "Clock", Section: "나의 업무"},
|
|
{Key: "projects", Label: "프로젝트", Path: "/projects", Icon: "FolderKanban", Section: "나의 업무"},
|
|
{Key: "incentive", Label: "인센티브", Path: "/incentive", Icon: "Coins", Section: "나의 업무"},
|
|
{Key: "profile", Label: "내 프로필", Path: "/profile", Icon: "UserCircle", Section: "나의 업무"},
|
|
{Key: "approvals", Label: "승인 관리", Path: "/admin/approvals", Icon: "CheckSquare", AdminOnly: true, Section: "관리자"},
|
|
{Key: "attendance-admin", Label: "근무 관리", Path: "/admin/attendance", Icon: "ClipboardList", AdminOnly: true, Section: "관리자"},
|
|
{Key: "projects-admin", Label: "프로젝트 관리", Path: "/admin/projects", Icon: "FolderCog", AdminOnly: true, Section: "관리자"},
|
|
{Key: "master", Label: "기준정보", Path: "/admin/master", Icon: "Database", AdminOnly: true, Section: "관리자"},
|
|
{Key: "incentive-admin", Label: "인센티브 관리", Path: "/admin/incentive", Icon: "Calculator", AdminOnly: true, Section: "관리자"},
|
|
{Key: "accounting", Label: "회계", Path: "/admin/accounting", Icon: "Wallet", AdminOnly: true, Section: "관리자"},
|
|
{Key: "members", Label: "구성원", Path: "/admin/members", Icon: "Users", AdminOnly: true, Section: "관리자"},
|
|
{Key: "settings", Label: "설정", Path: "/admin/settings", Icon: "Settings", AdminOnly: true, Section: "관리자"},
|
|
}
|
|
|
|
func (s *Server) handleNav(w http.ResponseWriter, r *http.Request) {
|
|
admin := s.isAdmin(r)
|
|
out := make([]NavItem, 0, len(navItems))
|
|
for _, it := range navItems {
|
|
if it.AdminOnly && !admin {
|
|
continue
|
|
}
|
|
out = append(out, it)
|
|
}
|
|
writeJSON(w, http.StatusOK, out)
|
|
}
|
|
|
|
// lc lower-cases & trims a string (small helper used across handlers).
|
|
func lc(s string) string { return strings.ToLower(strings.TrimSpace(s)) }
|