From f5a9c2235acedff5bb960c08371cd4e49bd62879 Mon Sep 17 00:00:00 2001
From: Pascal Bleser
Date: Wed, 1 Apr 2026 09:19:47 +0200
Subject: [PATCH] groupware: add GetIdentityChanges
---
.../groupware/pkg/groupware/api_identity.go | 33 +++++++++++++++++++
services/groupware/pkg/groupware/api_quota.go | 5 ++-
services/groupware/pkg/groupware/route.go | 2 ++
3 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/services/groupware/pkg/groupware/api_identity.go b/services/groupware/pkg/groupware/api_identity.go
index efca6bbaa3..0ef0a2be6f 100644
--- a/services/groupware/pkg/groupware/api_identity.go
+++ b/services/groupware/pkg/groupware/api_identity.go
@@ -126,3 +126,36 @@ func (g *Groupware) DeleteIdentity(w http.ResponseWriter, r *http.Request) {
}
})
}
+
+// Get changes to Identities since a given State
+// @api:tags identity,changes
+func (g *Groupware) GetIdentityChanges(w http.ResponseWriter, r *http.Request) {
+ g.respond(w, r, func(req Request) Response {
+ accountId, err := req.GetAccountIdForMail()
+ if err != nil {
+ return req.error(accountId, err)
+ }
+
+ l := req.logger.With().Str(logAccountId, accountId)
+
+ var maxChanges uint = 0
+ if v, ok, err := req.parseUIntParam(QueryParamMaxChanges, 0); err != nil {
+ return req.error(accountId, err)
+ } else if ok {
+ maxChanges = v
+ l = l.Uint(QueryParamMaxChanges, v)
+ }
+
+ sinceState := jmap.State(req.OptHeaderParamDoc(HeaderParamSince, "Specifies the state identifier from which on to list identity changes"))
+ l = l.Str(HeaderParamSince, log.SafeString(string(sinceState)))
+
+ logger := log.From(l)
+ changes, sessionState, state, lang, jerr := g.jmap.GetIdentityChanges(accountId, req.session, req.ctx, logger, req.language(), sinceState, maxChanges)
+ if jerr != nil {
+ return req.jmapError(accountId, jerr, sessionState, lang)
+ }
+ var body jmap.IdentityChanges = changes
+
+ return req.respond(accountId, body, sessionState, IdentityResponseObjectType, state)
+ })
+}
diff --git a/services/groupware/pkg/groupware/api_quota.go b/services/groupware/pkg/groupware/api_quota.go
index bbf6cc7947..1562acf8bf 100644
--- a/services/groupware/pkg/groupware/api_quota.go
+++ b/services/groupware/pkg/groupware/api_quota.go
@@ -65,7 +65,9 @@ func (g *Groupware) GetQuotaForAllAccounts(w http.ResponseWriter, r *http.Reques
})
}
-// Get changes to Contacts since a given State
+// currently unsupported in Stalwart:
+/*
+// Get changes to Quotas since a given State
// @api:tags contact,changes
func (g *Groupware) GetQuotaChanges(w http.ResponseWriter, r *http.Request) {
g.respond(w, r, func(req Request) Response {
@@ -97,3 +99,4 @@ func (g *Groupware) GetQuotaChanges(w http.ResponseWriter, r *http.Request) {
return req.respond(accountId, body, sessionState, QuotaResponseObjectType, state)
})
}
+*/
diff --git a/services/groupware/pkg/groupware/route.go b/services/groupware/pkg/groupware/route.go
index 57bca79502..8c65315f60 100644
--- a/services/groupware/pkg/groupware/route.go
+++ b/services/groupware/pkg/groupware/route.go
@@ -185,6 +185,8 @@ func (g *Groupware) Route(r chi.Router) {
r.Get("/contacts", g.GetContactsChanges)
r.Get("/calendars", g.GetCalendarChanges)
r.Get("/events", g.GetEventChanges)
+ // r.Get("/quotas", g.GetQuotaChanges)
+ r.Get("/identities", g.GetIdentityChanges)
})
r.Get("/objects", g.GetObjects)
r.Post("/objects", g.GetObjects)