Skip to content

Commit f144a7c

Browse files
committed
groupware: add addressbook and calendar creation APIs
* add Groupware APIs for creating and deleting addressbooks * add Groupware APIs for creating and deleting calendars * add JMAP APIs for creating and deleting addressbooks, calendars * add JMAP APIs to retrieve Principals * fix API tagging * move addressbook JMAP APIs into its own file * move addressbook Groupware APIs into its own file
1 parent b120b25 commit f144a7c

30 files changed

Lines changed: 1539 additions & 346 deletions

pkg/jmap/api_addressbook.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package jmap
2+
3+
import (
4+
"context"
5+
6+
"github.com/opencloud-eu/opencloud/pkg/log"
7+
)
8+
9+
var NS_ADDRESSBOOKS = ns(JmapContacts)
10+
11+
type AddressBooksResponse struct {
12+
AddressBooks []AddressBook `json:"addressbooks"`
13+
NotFound []string `json:"notFound,omitempty"`
14+
}
15+
16+
func (j *Client) GetAddressbooks(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (AddressBooksResponse, SessionState, State, Language, Error) {
17+
logger = j.logger("GetAddressbooks", session, logger)
18+
19+
cmd, err := j.request(session, logger, NS_ADDRESSBOOKS,
20+
invocation(CommandAddressBookGet, AddressBookGetCommand{AccountId: accountId, Ids: ids}, "0"),
21+
)
22+
if err != nil {
23+
return AddressBooksResponse{}, "", "", "", err
24+
}
25+
26+
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (AddressBooksResponse, State, Error) {
27+
var response AddressBookGetResponse
28+
err = retrieveResponseMatchParameters(logger, body, CommandAddressBookGet, "0", &response)
29+
if err != nil {
30+
return AddressBooksResponse{}, response.State, err
31+
}
32+
return AddressBooksResponse{
33+
AddressBooks: response.List,
34+
NotFound: response.NotFound,
35+
}, response.State, nil
36+
})
37+
}
38+
39+
type AddressBookChanges struct {
40+
HasMoreChanges bool `json:"hasMoreChanges"`
41+
OldState State `json:"oldState,omitempty"`
42+
NewState State `json:"newState"`
43+
Created []AddressBook `json:"created,omitempty"`
44+
Updated []AddressBook `json:"updated,omitempty"`
45+
Destroyed []string `json:"destroyed,omitempty"`
46+
}
47+
48+
// Retrieve Address Book changes since a given state.
49+
// @apidoc addressbook,changes
50+
func (j *Client) GetAddressbookChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, maxChanges uint) (AddressBookChanges, SessionState, State, Language, Error) {
51+
return changesTemplate(j, "GetAddressbookChanges", NS_ADDRESSBOOKS,
52+
CommandAddressBookChanges, CommandAddressBookGet,
53+
func() AddressBookChangesCommand {
54+
return AddressBookChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
55+
},
56+
func(path string, rof string) AddressBookGetRefCommand {
57+
return AddressBookGetRefCommand{
58+
AccountId: accountId,
59+
IdsRef: &ResultReference{
60+
Name: CommandAddressBookChanges,
61+
Path: path,
62+
ResultOf: rof,
63+
},
64+
}
65+
},
66+
func(resp AddressBookChangesResponse) (State, State, bool, []string) {
67+
return resp.OldState, resp.NewState, resp.HasMoreChanges, resp.Destroyed
68+
},
69+
func(resp AddressBookGetResponse) []AddressBook { return resp.List },
70+
func(oldState, newState State, hasMoreChanges bool, created, updated []AddressBook, destroyed []string) AddressBookChanges {
71+
return AddressBookChanges{
72+
OldState: oldState,
73+
NewState: newState,
74+
HasMoreChanges: hasMoreChanges,
75+
Created: created,
76+
Updated: updated,
77+
Destroyed: destroyed,
78+
}
79+
},
80+
func(resp AddressBookGetResponse) State { return resp.State },
81+
session, ctx, logger, acceptLanguage,
82+
)
83+
}
84+
85+
func (j *Client) CreateAddressBook(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, create AddressBookChange) (*AddressBook, SessionState, State, Language, Error) {
86+
return createTemplate(j, "CreateAddressBook", NS_ADDRESSBOOKS, AddressBookType, CommandAddressBookSet, CommandAddressBookGet,
87+
func(accountId string, create map[string]AddressBookChange) AddressBookSetCommand {
88+
return AddressBookSetCommand{AccountId: accountId, Create: create}
89+
},
90+
func(accountId string, ref string) AddressBookGetCommand {
91+
return AddressBookGetCommand{AccountId: accountId, Ids: []string{ref}}
92+
},
93+
func(resp AddressBookSetResponse) map[string]*AddressBook {
94+
return resp.Created
95+
},
96+
func(resp AddressBookSetResponse) map[string]SetError {
97+
return resp.NotCreated
98+
},
99+
func(resp AddressBookGetResponse) []AddressBook {
100+
return resp.List
101+
},
102+
func(resp AddressBookSetResponse) State {
103+
return resp.NewState
104+
},
105+
accountId, session, ctx, logger, acceptLanguage, create,
106+
)
107+
}
108+
109+
func (j *Client) DeleteAddressBook(accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
110+
return deleteTemplate(j, "DeleteAddressBook", NS_ADDRESSBOOKS, CommandAddressBookSet,
111+
func(accountId string, destroy []string) AddressBookSetCommand {
112+
return AddressBookSetCommand{AccountId: accountId, Destroy: destroy}
113+
},
114+
func(resp AddressBookSetResponse) map[string]SetError { return resp.NotDestroyed },
115+
func(resp AddressBookSetResponse) State { return resp.NewState },
116+
accountId, destroy, session, ctx, logger, acceptLanguage,
117+
)
118+
}

pkg/jmap/api_calendar.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ type CalendarEventChanges struct {
161161
Destroyed []string `json:"destroyed,omitempty"`
162162
}
163163

164+
// Retrieve the changes in Calendar Events since a given State.
165+
// @api:tags event,changes
164166
func (j *Client) GetCalendarEventChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
165167
acceptLanguage string, sinceState State, maxChanges uint) (CalendarEventChanges, SessionState, State, Language, Error) {
166168
return changesTemplate(j, "GetCalendarEventChanges", NS_CALENDARS,
@@ -229,3 +231,38 @@ func (j *Client) DeleteCalendarEvent(accountId string, destroy []string, session
229231
func(resp CalendarEventSetResponse) State { return resp.NewState },
230232
accountId, destroy, session, ctx, logger, acceptLanguage)
231233
}
234+
235+
func (j *Client) CreateCalendar(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, create CalendarChange) (*Calendar, SessionState, State, Language, Error) {
236+
return createTemplate(j, "CreateCalendar", NS_CALENDARS, CalendarType, CommandAddressBookSet, CommandAddressBookGet,
237+
func(accountId string, create map[string]CalendarChange) CalendarSetCommand {
238+
return CalendarSetCommand{AccountId: accountId, Create: create}
239+
},
240+
func(accountId string, ref string) CalendarGetCommand {
241+
return CalendarGetCommand{AccountId: accountId, Ids: []string{ref}}
242+
},
243+
func(resp CalendarSetResponse) map[string]*Calendar {
244+
return resp.Created
245+
},
246+
func(resp CalendarSetResponse) map[string]SetError {
247+
return resp.NotCreated
248+
},
249+
func(resp CalendarGetResponse) []Calendar {
250+
return resp.List
251+
},
252+
func(resp CalendarSetResponse) State {
253+
return resp.NewState
254+
},
255+
accountId, session, ctx, logger, acceptLanguage, create,
256+
)
257+
}
258+
259+
func (j *Client) DeleteCalendar(accountId string, destroy []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]SetError, SessionState, State, Language, Error) {
260+
return deleteTemplate(j, "DeleteCalendar", NS_ADDRESSBOOKS, CommandAddressBookSet,
261+
func(accountId string, destroy []string) CalendarSetCommand {
262+
return CalendarSetCommand{AccountId: accountId, Destroy: destroy}
263+
},
264+
func(resp CalendarSetResponse) map[string]SetError { return resp.NotDestroyed },
265+
func(resp CalendarSetResponse) State { return resp.NewState },
266+
accountId, destroy, session, ctx, logger, acceptLanguage,
267+
)
268+
}

pkg/jmap/api_changes.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ func (s StateMap) MarshalZerologObject(e *zerolog.Event) {
7474
// if s.Quotas != nil { e.Str("quotas", string(*s.Quotas)) }
7575
}
7676

77+
// Retrieve the changes in any type of objects at once since a given State.
78+
// @api:tags changes
7779
func (j *Client) GetChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, stateMap StateMap, maxChanges uint) (Changes, SessionState, State, Language, Error) { //NOSONAR
7880
logger = log.From(j.logger("GetChanges", session, logger).With().Object("state", stateMap).Uint("maxChanges", maxChanges))
7981

pkg/jmap/api_contact.go

Lines changed: 2 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -11,80 +11,6 @@ import (
1111

1212
var NS_CONTACTS = ns(JmapContacts)
1313

14-
type AddressBooksResponse struct {
15-
AddressBooks []AddressBook `json:"addressbooks"`
16-
NotFound []string `json:"notFound,omitempty"`
17-
}
18-
19-
func (j *Client) GetAddressbooks(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (AddressBooksResponse, SessionState, State, Language, Error) {
20-
logger = j.logger("GetAddressbooks", session, logger)
21-
22-
cmd, err := j.request(session, logger, NS_CONTACTS,
23-
invocation(CommandAddressBookGet, AddressBookGetCommand{AccountId: accountId, Ids: ids}, "0"),
24-
)
25-
if err != nil {
26-
return AddressBooksResponse{}, "", "", "", err
27-
}
28-
29-
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (AddressBooksResponse, State, Error) {
30-
var response AddressBookGetResponse
31-
err = retrieveResponseMatchParameters(logger, body, CommandAddressBookGet, "0", &response)
32-
if err != nil {
33-
return AddressBooksResponse{}, response.State, err
34-
}
35-
return AddressBooksResponse{
36-
AddressBooks: response.List,
37-
NotFound: response.NotFound,
38-
}, response.State, nil
39-
})
40-
}
41-
42-
type AddressBookChanges struct {
43-
HasMoreChanges bool `json:"hasMoreChanges"`
44-
OldState State `json:"oldState,omitempty"`
45-
NewState State `json:"newState"`
46-
Created []AddressBook `json:"created,omitempty"`
47-
Updated []AddressBook `json:"updated,omitempty"`
48-
Destroyed []string `json:"destroyed,omitempty"`
49-
}
50-
51-
// Retrieve Address Book changes since a given state.
52-
// @apidoc addressbook,changes
53-
func (j *Client) GetAddressbookChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, maxChanges uint) (AddressBookChanges, SessionState, State, Language, Error) {
54-
return changesTemplate(j, "GetAddressbookChanges", NS_CONTACTS,
55-
CommandAddressBookChanges, CommandAddressBookGet,
56-
func() AddressBookChangesCommand {
57-
return AddressBookChangesCommand{AccountId: accountId, SinceState: sinceState, MaxChanges: posUIntPtr(maxChanges)}
58-
},
59-
func(path string, rof string) AddressBookGetRefCommand {
60-
return AddressBookGetRefCommand{
61-
AccountId: accountId,
62-
IdsRef: &ResultReference{
63-
Name: CommandAddressBookChanges,
64-
Path: path,
65-
ResultOf: rof,
66-
},
67-
}
68-
},
69-
func(resp AddressBookChangesResponse) (State, State, bool, []string) {
70-
return resp.OldState, resp.NewState, resp.HasMoreChanges, resp.Destroyed
71-
},
72-
func(resp AddressBookGetResponse) []AddressBook { return resp.List },
73-
func(oldState, newState State, hasMoreChanges bool, created, updated []AddressBook, destroyed []string) AddressBookChanges {
74-
return AddressBookChanges{
75-
OldState: oldState,
76-
NewState: newState,
77-
HasMoreChanges: hasMoreChanges,
78-
Created: created,
79-
Updated: updated,
80-
Destroyed: destroyed,
81-
}
82-
},
83-
func(resp AddressBookGetResponse) State { return resp.State },
84-
session, ctx, logger, acceptLanguage,
85-
)
86-
}
87-
8814
func (j *Client) GetContactCardsById(accountId string, session *Session, ctx context.Context, logger *log.Logger,
8915
acceptLanguage string, contactIds []string) (map[string]jscontact.ContactCard, SessionState, State, Language, Error) {
9016
logger = j.logger("GetContactCardsById", session, logger)
@@ -132,6 +58,8 @@ type ContactCardChanges struct {
13258
Destroyed []string `json:"destroyed,omitempty"`
13359
}
13460

61+
// Retrieve the changes in Contact Cards since a given State.
62+
// @api:tags contact,changes
13563
func (j *Client) GetContactCardChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
13664
acceptLanguage string, sinceState State, maxChanges uint) (ContactCardChanges, SessionState, State, Language, Error) {
13765
return changesTemplate(j, "GetContactCardChanges", NS_CONTACTS,

pkg/jmap/api_email.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ type EmailChanges struct {
204204
Destroyed []string `json:"destroyed,omitempty"`
205205
}
206206

207-
// Get all the Emails that have been created, updated or deleted since a given state.
207+
// Retrieve the changes in Emails since a given State.
208+
// @api:tags email,changes
208209
func (j *Client) GetEmailChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceState State, fetchBodies bool, maxBodyValueBytes uint, maxChanges uint) (EmailChanges, SessionState, State, Language, Error) { //NOSONAR
209210
logger = j.loggerParams("GetEmailChanges", session, logger, func(z zerolog.Context) zerolog.Context {
210211
return z.Bool(logFetchBodies, fetchBodies).Str(logSinceState, string(sinceState))
@@ -1080,6 +1081,8 @@ type EmailSubmissionChanges struct {
10801081
Destroyed []string `json:"destroyed,omitempty"`
10811082
}
10821083

1084+
// Retrieve the changes in Email Submissions since a given State.
1085+
// @api:tags email,changes
10831086
func (j *Client) GetEmailSubmissionChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
10841087
acceptLanguage string, sinceState State, maxChanges uint) (EmailSubmissionChanges, SessionState, State, Language, Error) {
10851088
return changesTemplate(j, "GetEmailSubmissionChanges", NS_MAIL_SUBMISSION,

pkg/jmap/api_identity.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ type IdentityChanges struct {
180180
Destroyed []string `json:"destroyed,omitempty"`
181181
}
182182

183+
// Retrieve the changes in Email Identities since a given State.
184+
// @api:tags email,changes
183185
func (j *Client) GetIdentityChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
184186
acceptLanguage string, sinceState State, maxChanges uint) (IdentityChanges, SessionState, State, Language, Error) {
185187
return changesTemplate(j, "GetIdentityChanges", NS_IDENTITY,

pkg/jmap/api_mailbox.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var NS_MAILBOX = ns(JmapMail)
1313

1414
type MailboxesResponse struct {
1515
Mailboxes []Mailbox `json:"mailboxes"`
16-
NotFound []any `json:"notFound"`
16+
NotFound []string `json:"notFound"`
1717
}
1818

1919
func (j *Client) GetMailbox(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (MailboxesResponse, SessionState, State, Language, Error) {
@@ -172,6 +172,7 @@ func (j *Client) GetMailboxChanges(accountId string, session *Session, ctx conte
172172
}
173173

174174
// Retrieve Mailbox changes of multiple Accounts.
175+
// @api:tags email,changes
175176
func (j *Client) GetMailboxChangesForMultipleAccounts(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, sinceStateMap map[string]State, maxChanges uint) (map[string]MailboxChanges, SessionState, State, Language, Error) { //NOSONAR
176177
return changesTemplateN(j, "GetMailboxChangesForMultipleAccounts", NS_MAILBOX,
177178
accountIds, sinceStateMap, CommandMailboxChanges, CommandMailboxGet,

pkg/jmap/api_objects.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type Objects struct {
2020
EmailSubmissions *EmailSubmissionGetResponse `json:"submissions,omitempty"`
2121
}
2222

23+
// Retrieve objects of all types by their identifiers in a single batch.
24+
// @api:tags changes
2325
func (j *Client) GetObjects(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, //NOSONAR
2426
mailboxIds []string, emailIds []string,
2527
addressbookIds []string, contactIds []string,

pkg/jmap/api_principal.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package jmap
2+
3+
import (
4+
"context"
5+
6+
"github.com/opencloud-eu/opencloud/pkg/log"
7+
)
8+
9+
var NS_PRINCIPALS = ns(JmapPrincipals)
10+
11+
type PrincipalsResponse struct {
12+
Principals []Principal `json:"principals"`
13+
NotFound []string `json:"notFound,omitempty"`
14+
}
15+
16+
func (j *Client) GetPrincipals(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, ids []string) (PrincipalsResponse, SessionState, State, Language, Error) {
17+
logger = j.logger("GetPrincipals", session, logger)
18+
19+
cmd, err := j.request(session, logger, NS_PRINCIPALS,
20+
invocation(CommandPrincipalGet, PrincipalGetCommand{AccountId: accountId, Ids: ids}, "0"),
21+
)
22+
if err != nil {
23+
return PrincipalsResponse{}, "", "", "", err
24+
}
25+
26+
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (PrincipalsResponse, State, Error) {
27+
var response PrincipalGetResponse
28+
err = retrieveResponseMatchParameters(logger, body, CommandPrincipalGet, "0", &response)
29+
if err != nil {
30+
return PrincipalsResponse{}, response.State, err
31+
}
32+
return PrincipalsResponse{
33+
Principals: response.List,
34+
NotFound: response.NotFound,
35+
}, response.State, nil
36+
})
37+
}

pkg/jmap/api_quota.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type QuotaChanges struct {
2929
Destroyed []string `json:"destroyed,omitempty"`
3030
}
3131

32+
// Retrieve the changes in Quotas since a given State.
33+
// @api:tags quota,changes
3234
func (j *Client) GetQuotaChanges(accountId string, session *Session, ctx context.Context, logger *log.Logger,
3335
acceptLanguage string, sinceState State, maxChanges uint) (QuotaChanges, SessionState, State, Language, Error) {
3436
return changesTemplate(j, "GetQuotaChanges", NS_QUOTA,

0 commit comments

Comments
 (0)