Class CaldavCalendarShareService
Every check lives here, and none of them takes anything from the browser but a calendar id and a login:
- the calendar exists and the caller owns it — a space calendar, owned by its space, is refused, and so is a colleague's;
- the caller's account is connected, and the calendar is bound either to
a collection eXo created for it — an
SyncOrigin.EXOpair, active, whose collection carries the slug eXo derives from the calendar's own anchor — or to an imported collection the caller really owns: an active, anchoredSyncOrigin.REMOTEpair that is not the meetings mirror, whose ownership is confirmed on the server before its access list is read or anything is changed (only the capability probe, which selects the rule, comes first) (on RFC 3744 servers itsDAV:owneris the caller's recorded principal, it is writable for them and it sits under their calendar home; on BlueMind its path is under the caller's own uid, it is no subscription to someone else's calendar, and BlueMind's REST access list gives the callerAllorManage). The collection is resolved from the pair and never named by the request, so a share, a hidden share, the mirror or any other collection cannot be addressed; the client'sCalDavClient.writeAcl(org.exoplatform.caldav.client.CalDavEndpoint, org.exoplatform.caldav.model.CalendarSync, java.util.List<org.exoplatform.caldav.client.AccessControlEntry>)applies the pair rule again; - the server offers a granting mechanism whose every change eXo confirms
(
SharingMechanism) — Stalwart's RFC 3744ACLmethod, or BlueMind'sCS:shareconfirmed through its REST API; - the sharee is an eXo user, not the caller, connected to the same server registration, whose principal was recorded by a discovery (EXO-90243) and is not the caller's own principal — two eXo users on one login would be "sharing" with themselves.
Read-modify-write, never overwrite. RFC 3744 §8.1 has an ACL
request replace every entry that is neither protected nor inherited, and
Stalwart replaces its grant list the same way. So a grant reads the list,
keeps every modifiable entry — including entries eXo did not write, a share
made from another client — adds one DAV:read grant, and writes the
list back; a revoke removes that principal's read-only grants and nothing
else. A list with an entry the client cannot represent is never written.
Protected and inherited entries are never sent: the server keeps them.
What a list read over DAV cannot carry back. A server's access list
over DAV is a projection of its own rights, and not a faithful one: on
Stalwart (source, crates/dav/src/common/acl.rs and
crates/jmap-proto/src/object/calendar.rs, main 474dd022)
a colleague given "may delete" or "may write all" through JMAP reads back
as DAV:write, and that entry written back becomes full write — eXo
would widen somebody's rights by sharing with somebody else. Every
widening is an entry reading back with more than the read-only privileges,
so another principal holding any such entry stops the write
(FOREIGN_ACCESS_NOT_PRESERVED), and the owner manages that
calendar's access where it was set. What remains is narrowing: rights DAV
does not show at all (JMAP "may write own", "may update private", "may
RSVP"; the invite and reply parts of a scheduling grant) sit behind a
read-only entry and are dropped when it is written back. That is accepted
as the lesser loss, and stated here so it is a decision rather than a
surprise.
Verified, not claimed. The list is read again after every write, and a grant absent from it — or a revoked grant still in it — is reported as not applied, whatever status the write answered.
Nothing is stored. Who a calendar is shared with is the server's
state and anyone's other client can change it, so every listing reads it
afresh. Concurrent edits by this node are serialised per collection; edits
from another node or another client at the same moment are last writer
wins, because RFC 3744 offers no conditional ACL request. Each
applied grant and revoke is logged at info: who, to whom, which calendar.
On BlueMind (SharingMechanism.BLUEMIND_SHARE) the change is a
POST CS:share naming the colleague by the mail address their own
principal publishes, and the proof is the container's access list read back
through BlueMind's REST API with the owner's credentials. A colleague sees
the calendar only once they subscribed to it in BlueMind, which the listing
says (subscriptionRequired).
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordA calendar's collection on the caller's server and the shares read from it, both from one resolution of the calendar (EXO-90385).static final recordA calendar's collection on the caller's server. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringThe access list holds an entry eXo cannot write back faithfully.static final StringThe server would not let the caller read the calendar's access list.static final StringThe calendar does not exist, or was deleted.static final StringThe calendar is bound to no collection eXo can share: none eXo created for it, and no active imported one.static final StringThe server refused the account's stored credentials.static final StringAnother principal holds access beyond seeing the calendar, which writing the list back could change on the server.static final StringThe server accepted the change, and the list read back does not hold it.static final StringThe caller has no connected CalDAV account.static final StringThe imported collection is not the caller's own on the server: another principal owns it, it is read-only for them, it lies outside their calendar home, it is a subscription to someone else's calendar, or the server gives them no right to manage who sees it.static final StringThe caller does not own the calendar.static final StringThe sharee holds more than read access, granted outside eXo.static final StringThe server offers no way to grant access whose changes eXo can confirm.static final StringNeither the server nor eXo's record says which principal the caller is connected as, so a colleague on the caller's own login cannot be told apart.static final StringThe sharee is connected to the server as the caller's own principal.static final StringThe server refused the change.static final StringThe server could not be reached or answered something unusable.static final StringThe server named no mail address for the sharee's principal, which is the only way BlueMind's share handler finds a sharee.static final StringThe colleague holds access below viewing given outside eXo — seeing when the owner is free, say — which a share from eXo would replace and a later stop would erase.static final StringThe sharee is the caller.static final StringThe sharee has no recorded identity on the same server.static final StringNo sharee was named.static final StringThe sharee is not a known, active eXo user. -
Constructor Summary
ConstructorsConstructorDescriptionCaldavCalendarShareService(org.exoplatform.agenda.service.AgendaCalendarService agendaCalendarService, CaldavConnectorStorage caldavConnectorStorage, CaldavSyncStorage caldavSyncStorage, CalDavClient calDavClient, CaldavConnectionIdentityService caldavConnectionIdentityService, org.exoplatform.social.core.manager.IdentityManager identityManager, BlueMindAclClient blueMindAclClient, CaldavPushService caldavPushService, CaldavShareSubscriptionService caldavShareSubscriptionService, CaldavServerOwnerService caldavServerOwnerService, CaldavServerService caldavServerService, long probeMemoSeconds) -
Method Summary
Modifier and TypeMethodDescriptionList<org.exoplatform.caldav.model.CalendarShares.ShareUser> candidates(long userIdentityId, String username, long calendarId, String query) The colleagues a calendar of the caller's can be shared with: eXo users connected to the same server registration, with a recorded principal that is not the caller's own.org.exoplatform.caldav.model.CalendarSharesGives one colleague read access to a calendar of the caller's.org.exoplatform.caldav.model.CalendarSharesgrant(long userIdentityId, String username, long calendarId, String shareeUsername, org.exoplatform.caldav.model.CalendarShares.ShareAccess access) Gives one colleague access to a calendar of the caller's, at the level asked for (EXO-90378).booleanholdsMeetingCopies(long userIdentityId, String username, long calendarId) Whether a calendar of the caller's, on their server, is where their eXo meeting copies are written (EXO-90357): what agenda's Share drawer asks before sharing it, through this add-on's channel plugin.org.exoplatform.caldav.model.CalendarShareslistShares(long userIdentityId, String username, long calendarId) Who a calendar of the caller's is shared with, read from the server now.org.exoplatform.caldav.model.CalendarSharesTakes access to a calendar of the caller's away from one colleague, whichever level eXo granted it at.serverShares(long userIdentityId, String username, long calendarId) Who a calendar of the caller's is shared with, and the collection those shares live on, from one resolution of the calendar (EXO-90385).shareableCalendarIds(long userIdentityId, String username) The caller's calendars that can be shared from eXo: owned, bound to a collection eXo created or to an imported collection they own on the server, on a server offering a mechanism whose changes eXo can confirm.sharedCollectionOf(long userIdentityId, String username, long calendarId) The collection a calendar of the caller's is bound to on their server, and that server (EXO-90357): what agenda records on a share this add-on delivered, so the sharee's own listing of the server's collections can be told from it.
-
Field Details
-
CALENDAR_NOT_FOUND
The calendar does not exist, or was deleted.- See Also:
-
NOT_OWNER
The caller does not own the calendar.- See Also:
-
NOT_CONNECTED
The caller has no connected CalDAV account.- See Also:
-
CALENDAR_NOT_ON_SERVER
The calendar is bound to no collection eXo can share: none eXo created for it, and no active imported one.- See Also:
-
NOT_OWNED_ON_SERVER
The imported collection is not the caller's own on the server: another principal owns it, it is read-only for them, it lies outside their calendar home, it is a subscription to someone else's calendar, or the server gives them no right to manage who sees it.- See Also:
-
NOT_SUPPORTED
The server offers no way to grant access whose changes eXo can confirm.- See Also:
-
SHAREE_REQUIRED
No sharee was named.- See Also:
-
SHAREE_UNKNOWN
The sharee is not a known, active eXo user.- See Also:
-
SHAREE_IS_OWNER
The sharee is the caller.- See Also:
-
SHAREE_NOT_CONNECTED
The sharee has no recorded identity on the same server.- See Also:
-
SAME_PRINCIPAL
The sharee is connected to the server as the caller's own principal.- See Also:
-
NOT_READ_ONLY
The sharee holds more than read access, granted outside eXo.- See Also:
-
ACL_UNREADABLE
The server would not let the caller read the calendar's access list.- See Also:
-
ACL_NOT_UNDERSTOOD
The access list holds an entry eXo cannot write back faithfully.- See Also:
-
SERVER_REFUSED
The server refused the change.- See Also:
-
OWNER_UNKNOWN
Neither the server nor eXo's record says which principal the caller is connected as, so a colleague on the caller's own login cannot be told apart.- See Also:
-
SHAREE_ADDRESS_UNKNOWN
The server named no mail address for the sharee's principal, which is the only way BlueMind's share handler finds a sharee.- See Also:
-
SHAREE_HAS_OTHER_ACCESS
The colleague holds access below viewing given outside eXo — seeing when the owner is free, say — which a share from eXo would replace and a later stop would erase.- See Also:
-
FOREIGN_ACCESS_NOT_PRESERVED
Another principal holds access beyond seeing the calendar, which writing the list back could change on the server.- See Also:
-
NOT_APPLIED
The server accepted the change, and the list read back does not hold it.- See Also:
-
SERVER_UNAVAILABLE
The server could not be reached or answered something unusable.- See Also:
-
CREDENTIALS
The server refused the account's stored credentials.- See Also:
-
-
Constructor Details
-
Method Details
-
grant
public org.exoplatform.caldav.model.CalendarShares grant(long userIdentityId, String username, long calendarId, String shareeUsername) throws org.exoplatform.commons.exception.ObjectNotFoundException, IllegalAccessException Gives one colleague read access to a calendar of the caller's.Idempotent: a colleague who can already read it — through a grant eXo made or one made elsewhere — is left as they are and nothing is written. On BlueMind that holds for plain view access only: its access list shows a colleague holding more as reading too, and such a colleague is refused (
NOT_READ_ONLY) rather than rewritten, as is one holding only other access given outside eXo (SHAREE_HAS_OTHER_ACCESS).- Parameters:
userIdentityId- the callerusername- the caller's logincalendarId- the agenda calendarshareeUsername- the colleague's login- Returns:
- the sharees as the server lists them after the grant
- Throws:
org.exoplatform.commons.exception.ObjectNotFoundException- when the calendar does not existIllegalAccessException- when the caller does not own itIllegalArgumentException- with acaldav.share.*code when the calendar or the sharee cannot be shared withCaldavShareException- when the account, the server or its answer stops the grant
-
revoke
public org.exoplatform.caldav.model.CalendarShares revoke(long userIdentityId, String username, long calendarId, String shareeUsername) throws org.exoplatform.commons.exception.ObjectNotFoundException, IllegalAccessException Takes access to a calendar of the caller's away from one colleague, whichever level eXo granted it at.Removes that colleague's eXo-shaped grants — a read grant, or an edit grant (EXO-90378) — and nothing else; a grant of any other shape was made outside eXo, is not eXo's to take back, and the whole request is refused rather than half applied. Idempotent: a colleague with no grant is left alone and nothing is written.
- Parameters:
userIdentityId- the callerusername- the caller's logincalendarId- the agenda calendarshareeUsername- the colleague's login- Returns:
- the sharees as the server lists them after the revoke
- Throws:
org.exoplatform.commons.exception.ObjectNotFoundException- when the calendar does not existIllegalAccessException- when the caller does not own itIllegalArgumentException- with acaldav.share.*code when the calendar or the sharee cannot be handledCaldavShareException- when the account, the server or its answer stops the revoke
-
candidates
public List<org.exoplatform.caldav.model.CalendarShares.ShareUser> candidates(long userIdentityId, String username, long calendarId, String query) throws org.exoplatform.commons.exception.ObjectNotFoundException, IllegalAccessException The colleagues a calendar of the caller's can be shared with: eXo users connected to the same server registration, with a recorded principal that is not the caller's own.Listed per eXo user, while a grant names a principal: two eXo users connected under one DAV login are two candidates, and granting to either gives both access — the server knows the login, not the person.
listShares(long, java.lang.String, long)then names every user the grant reached (CalendarShares.CalendarSharee.users()). Whether the picker should say so before the grant, by grouping candidates per principal, is a product decision this method leaves open.The server is asked what the collection advertises, the capability check the listing, the grant and the revoke make, so that nobody is listed on a server where eXo offers no sharing. The colleagues themselves are read from eXo's own record of each connection; the server is asked who the caller is only when that is not recorded yet. Bounded by the storage's read of the server's connections; a colleague beyond that bound is not offered.
- Parameters:
userIdentityId- the callerusername- the caller's logincalendarId- the agenda calendarquery- text their login or full name must contain, ignoring case; blank for everyone- Returns:
- the candidates, by full name
- Throws:
org.exoplatform.commons.exception.ObjectNotFoundException- when the calendar does not existIllegalAccessException- when the caller does not own itIllegalArgumentException- when it is bound to no collection eXo can shareCaldavShareException- when sharing is not offered on the server, the credentials are refused, the server cannot be reached, the caller's principal cannot be named, or the calendar is an imported one the caller does not own on the server
-
holdsMeetingCopies
public boolean holdsMeetingCopies(long userIdentityId, String username, long calendarId) throws org.exoplatform.commons.exception.ObjectNotFoundException, IllegalAccessException Whether a calendar of the caller's, on their server, is where their eXo meeting copies are written (EXO-90357): what agenda's Share drawer asks before sharing it, through this add-on's channel plugin. A read, so eXo's own record of the destination answers when it may (meetingCopiesOf(org.exoplatform.caldav.service.CaldavCalendarShareService.ShareTarget, java.lang.String, boolean)), and the server is asked only when it may not.- Parameters:
userIdentityId- the callerusername- the caller's logincalendarId- the agenda calendar- Returns:
- true when the calendar holds the meeting copies; false when it does not, or is not on the caller's server at all
- Throws:
org.exoplatform.commons.exception.ObjectNotFoundException- when the calendar does not existIllegalAccessException- when the caller does not own it