groupware: add real calendars and events

This commit is contained in:
Pascal Bleser
2025-10-30 15:12:08 +01:00
parent 1d66edf0d0
commit 0e1be0c5cc
10 changed files with 1400 additions and 58 deletions

View File

@@ -31,9 +31,13 @@ func (g *Groupware) GetCalendars(w http.ResponseWriter, r *http.Request) {
if !ok {
return resp
}
var _ string = accountId
return response(AllCalendars, req.session.State, "")
calendars, sessionState, state, lang, jerr := g.jmap.GetCalendars(accountId, req.session, req.ctx, req.logger, req.language(), nil)
if jerr != nil {
return req.errorResponseFromJmap(jerr)
}
return etagResponse(calendars, sessionState, state, lang)
})
}
@@ -61,16 +65,23 @@ func (g *Groupware) GetCalendarById(w http.ResponseWriter, r *http.Request) {
if !ok {
return resp
}
var _ string = accountId
l := req.logger.With()
calendarId := chi.URLParam(r, UriParamCalendarId)
// TODO replace with proper implementation
for _, calendar := range AllCalendars {
if calendar.Id == calendarId {
return response(calendar, req.session.State, "")
}
l = l.Str(UriParamCalendarId, log.SafeString(calendarId))
logger := log.From(l)
calendars, sessionState, state, lang, jerr := g.jmap.GetCalendars(accountId, req.session, req.ctx, logger, req.language(), []string{calendarId})
if jerr != nil {
return req.errorResponseFromJmap(jerr)
}
if len(calendars.NotFound) > 0 {
return notFoundResponse(sessionState)
} else {
return etagResponse(calendars.Calendars[0], sessionState, state, lang)
}
return notFoundResponse(req.session.State)
})
}
@@ -96,15 +107,109 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request)
if !ok {
return resp
}
var _ string = accountId
l := req.logger.With()
calendarId := chi.URLParam(r, UriParamCalendarId)
// TODO replace with proper implementation
events, ok := EventsMapByCalendarId[calendarId]
if !ok {
return notFoundResponse(req.session.State)
l = l.Str(UriParamCalendarId, log.SafeString(calendarId))
offset, ok, err := req.parseUIntParam(QueryParamOffset, 0)
if err != nil {
return errorResponse(err)
}
return response(events, req.session.State, "")
if ok {
l = l.Uint(QueryParamOffset, offset)
}
limit, ok, err := req.parseUIntParam(QueryParamLimit, g.defaultContactLimit)
if err != nil {
return errorResponse(err)
}
if ok {
l = l.Uint(QueryParamLimit, limit)
}
filter := jmap.CalendarEventFilterCondition{
InCalendar: calendarId,
}
sortBy := []jmap.CalendarEventComparator{{Property: jmap.CalendarEventPropertyUpdated, IsAscending: false}}
logger := log.From(l)
eventsByAccountId, sessionState, state, lang, jerr := g.jmap.QueryCalendarEvents([]string{accountId}, req.session, req.ctx, logger, req.language(), filter, sortBy, offset, limit)
if jerr != nil {
return req.errorResponseFromJmap(jerr)
}
if events, ok := eventsByAccountId[accountId]; ok {
return etagResponse(events, sessionState, state, lang)
} else {
return notFoundResponse(sessionState)
}
})
}
func (g *Groupware) CreateCalendarEvent(w http.ResponseWriter, r *http.Request) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := req.needCalendarWithAccount()
if !ok {
return resp
}
l := req.logger.With()
calendarId := chi.URLParam(r, UriParamCalendarId)
l = l.Str(UriParamCalendarId, log.SafeString(calendarId))
var create jmap.CalendarEvent
err := req.body(&create)
if err != nil {
return errorResponse(err)
}
logger := log.From(l)
created, sessionState, state, lang, jerr := g.jmap.CreateCalendarEvent(accountId, req.session, req.ctx, logger, req.language(), create)
if jerr != nil {
return req.errorResponseFromJmap(jerr)
}
return etagResponse(created, sessionState, state, lang)
})
}
func (g *Groupware) DeleteCalendarEvent(w http.ResponseWriter, r *http.Request) {
g.respond(w, r, func(req Request) Response {
ok, accountId, resp := req.needCalendarWithAccount()
if !ok {
return resp
}
l := req.logger.With().Str(accountId, log.SafeString(accountId))
calendarId := chi.URLParam(r, UriParamCalendarId)
eventId := chi.URLParam(r, UriParamEventId)
l.Str(UriParamCalendarId, log.SafeString(calendarId)).Str(UriParamEventId, log.SafeString(eventId))
logger := log.From(l)
deleted, sessionState, state, _, jerr := g.jmap.DeleteCalendarEvent(accountId, []string{eventId}, req.session, req.ctx, logger, req.language())
if jerr != nil {
return req.errorResponseFromJmap(jerr)
}
for _, e := range deleted {
desc := e.Description
if desc != "" {
return errorResponseWithSessionState(apiError(
req.errorId(),
ErrorFailedToDeleteContact,
withDetail(e.Description),
), sessionState)
} else {
return errorResponseWithSessionState(apiError(
req.errorId(),
ErrorFailedToDeleteContact,
), sessionState)
}
}
return noContentResponseWithEtag(sessionState, state)
})
}

View File

@@ -73,7 +73,7 @@ var E1 = jmap.CalendarEvent{
UtcEnd: jmap.UTCDate{Time: mustParseTime("2025-10-07T00:00:00Z")},
Event: jscalendar.Event{
Type: jscalendar.EventType,
Start: jscalendar.LocalDateTime{Time: mustParseTime("2025-09-30T12:00:00Z")},
Start: jscalendar.LocalDateTime("2025-09-30T12:00:00"),
Duration: "PT30M",
Status: jscalendar.StatusConfirmed,
Object: jscalendar.Object{
@@ -146,16 +146,14 @@ var E1 = jmap.CalendarEvent{
},
},
},
RecurrenceRules: []jscalendar.RecurrenceRule{
{
Type: jscalendar.RecurrenceRuleType,
Frequency: jscalendar.FrequencyWeekly,
Interval: 1,
Rscale: jscalendar.RscaleIso8601,
Skip: jscalendar.SkipOmit,
FirstDayOfWeek: jscalendar.DayOfWeekMonday,
Count: 4,
},
RecurrenceRule: &jscalendar.RecurrenceRule{
Type: jscalendar.RecurrenceRuleType,
Frequency: jscalendar.FrequencyWeekly,
Interval: 1,
Rscale: jscalendar.RscaleIso8601,
Skip: jscalendar.SkipOmit,
FirstDayOfWeek: jscalendar.DayOfWeekMonday,
Count: 4,
},
FreeBusyStatus: jscalendar.FreeBusyStatusBusy,
Privacy: jscalendar.PrivacyPublic,

View File

@@ -148,8 +148,8 @@ var T1 = jmap.Task{
MayInviteOthers: true,
HideAttendees: true,
},
Due: jscalendar.LocalDateTime{Time: mustParseTime("2025-12-01T10:11:12Z")},
Start: jscalendar.LocalDateTime{Time: mustParseTime("2025-10-01T08:00:00Z")},
Due: jscalendar.LocalDateTime("2025-12-01T10:11:12"),
Start: jscalendar.LocalDateTime("2025-10-01T08:00:00"),
EstimatedDuration: "PT8W",
PercentComplete: 5,
Progress: jscalendar.ProgressNeedsAction,

View File

@@ -23,6 +23,7 @@ const (
UriParamCalendarId = "calendarid"
UriParamTaskListId = "tasklistid"
UriParamContactId = "contactid"
UriParamEventId = "eventid"
QueryParamMailboxSearchName = "name"
QueryParamMailboxSearchRole = "role"
QueryParamMailboxSearchSubscribed = "subscribed"
@@ -154,6 +155,10 @@ func (g *Groupware) Route(r chi.Router) {
r.Get("/", g.GetCalendarById)
r.Get("/events", g.GetEventsInCalendar)
})
r.Route("/events", func(r chi.Router) {
r.Post("/", g.CreateCalendarEvent)
r.Delete("/{eventid}", g.DeleteCalendarEvent)
})
})
r.Route("/tasklists", func(r chi.Router) {
r.Get("/", g.GetTaskLists)