You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Share calendar to users or groups with "show only as busy". #11214
After the steps to reproduce the behavior I want to choose an option "show only as busy". So, that the selected user or group can see my complete calendar but without details. This option is missing.
I know that it is possible for a single event to "show only as busy". But what if I want to have this for a specific user or group for the complete calendar?
Actual behaviour
After the steps to reproduce the behavior there is only an option "can edit" for the chosen user or group.
GitMate.io thinks possibly related issues are #8698 (need a group or folder for all user), #7340 (Show circle name in details of a shared file (group user)), #866 (Calendar Share Functionality missing), #10347 (Make shares visible to other users), and #3801 (Adding appointment into shared calendar fails).
Ideally it'd be possible to do this for calendar links as well. (And to be able to generate links for both full access and free/busy simultaneously.) Google Calendar for example only lets you do one or the other at any given time.
Reacted by dusscloud, qq7te, dmjk, Christian Häusler, Colin Tück, Kilian Evang, sphuo5g and Andreas Pahler
@stefanoco
Would you like add to my bounty on this? I have a couple of freelance programers who I am working with on other projects, they might be able to contribute on short notice....
@georgehrke
Could we setup a group chat somewhere for us and the programers, to discuss scope and for you to give clear directions? Could make life easier, in the end...
This would be really important to avoid accidentally publishing event details to a shared calendar. Right now, events seem to default to "when shared, show full event". This may accidentally expose private information when creating an event from a phone or app that doesn't expose the "when shared show" field.
Is it possible to change the default value for "when shared show" field to "when shared, show only busy"?
Reacted by Ozan Öğreden, Tobias Strobel, nolens, Choupinounours, paradeiser, mrwsl, bronwynlapham and Christian Häusler
This report is about a demanded new feature for sharing a whole calendar as "only show me busy".
I'd like to have a consumer for my calendar that should never see the details of events but others should.
Reacted by Kay Strobach, Kevin, Benjamin Orgis, paradeiser, Richard Steinmetz, sokai, mich, phipz, Bodo08 and Ben Curtis
I wrote now a small(?) python script that "solves" this problem for me. It "copies" the entries from some calenders into another one. Either just with predefined Title/Summary or copying the original title/summary after the predefined one (e.g. if some details shouldn't be shared that might be in the notes) but it's ok to get an overall idea what the appointment is about.
fromcaldavimporterror, get_davclientimportcalendarfromdatetimeimportdatetime, timedeltaimporticalendar# Calendars with title# Name (used in the copied events): URLcalendars_with_title= {\
"Private":"https://nextcloud/dav/calendars/user/calendar_name/"
}
# Calendars with only "busy"# Name (used in the copied events): URLcalendars_only_busy= {\
"Work":"https://nextcloud/dav/calendars/user/calendar_name/"
}
# Destination calendartarget_calendar="https://nextcloud/dav/calendars/user/calendar_name/"## Helpers#defreplace_calendar_url_by_object(url, calendars):
forcalendarincalendars:
ifurl==calendar.url:
returncalendardefreplace_calendar_urls_in_dictionary_by_object(dictionary, calendars):
forkeyindictionary:
dictionary[key] =replace_calendar_url_by_object(dictionary[key], calendars)
returndictionarydefdelete_old_entries(calendar, min_age):
old_events=calendar.search(
start=datetime.now() +timedelta(days=-2*min_age),
end=datetime.now() +timedelta(days=-1*min_age),
event=True,
expand=True,
)
foreventinold_events:
event.delete()
defget_next_event_from_iterator(iterator):
try:
event=iterator.__next__()
returneventexcept:
returnNonedefget_event(raw_event):
forcomponentinraw_event.get_icalendar_instance().subcomponents:
ifisinstance(component, icalendar.cal.Event):
returncomponentdefsync_calender(source, target, name, copy_summary=False):
# get events in the relevant intervallsource_events=source.search(
start=datetime.now(),
end=datetime.now() +timedelta(days=270),
event=True,
expand=True,
)
target_events=target.search(
start=datetime.now(),
end=datetime.now() +timedelta(days=270),
event=True,
expand=True,
)
# sort according to start timesource_events.sort(key=lambdaself: calendar.timegm(get_event(self)["DTSTART"].dt.timetuple()))
target_events.sort(key=lambdaself: calendar.timegm(get_event(self)["DTSTART"].dt.timetuple()))
# get iteratorssource_iter=source_events.__iter__()
target_iter=target_events.__iter__()
# get first eventcurrent_source_event=get_next_event_from_iterator(source_iter)
current_target_event=get_next_event_from_iterator(target_iter)
# both calendars still have eventswhilecurrent_source_event!=Noneandcurrent_target_event!=None:
source_vevent=get_event(current_source_event)
target_vevent=get_event(current_target_event)
# make sure the event in the target calender is for the source, else proceed forwardiftarget_vevent["SUMMARY"].find(name) !=0:
current_target_event=get_next_event_from_iterator(target_iter)
continue# we have two events for the source calender, now lets check if they are sufficient identicalifcopy_summary:
target_summary=name+": "+source_vevent["SUMMARY"]
else:
target_summary=nameiftarget_vevent["SUMMARY"] ==target_summary \
andsource_vevent["DTSTART"].dt==target_vevent["DTSTART"].dt \
andsource_vevent["DTEND"].dt==target_vevent["DTEND"].dt:
# entries are suffienctly identical, proced to the next onescurrent_source_event=get_next_event_from_iterator(source_iter)
current_target_event=get_next_event_from_iterator(target_iter)
continue# the events are different# first case, the one in the target starts earlier (or at the same time) => delete that oneifsource_vevent["DTSTART"].dt>=target_vevent["DTSTART"].dt:
current_target_event.delete()
current_target_event=get_next_event_from_iterator(target_iter)
continue# second case, the one in the source starts earlier, => create a new eventifsource_vevent["DTSTART"].dt<target_vevent["DTSTART"].dt:
target.add_event(
dtstart=source_vevent["DTSTART"],
dtend=source_vevent["DTEND"],
summary=target_summary,)
current_source_event=get_next_event_from_iterator(source_iter)
continue# While loop finished, one or both calendars have no remaining eventsassertcurrent_source_event==Noneorcurrent_target_event==None# target still has some events, delete if matching the sourcewhilecurrent_target_event!=None:
target_vevent=get_event(current_target_event)
# originally from the source calendariftarget_vevent["SUMMARY"].find(name) ==0:
current_target_event.delete()
# check nextcurrent_target_event=get_next_event_from_iterator(target_iter)
# source has still some events, add those to the targetwhilecurrent_source_event!=None:
source_vevent=get_event(current_source_event)
# originally from the source calendarifcopy_summary:
target_summary=name+": "+source_vevent["SUMMARY"]
else:
target_summary=nametarget.add_event(
dtstart=source_vevent["DTSTART"],
dtend=source_vevent["DTEND"],
summary=target_summary,)
# check nextcurrent_source_event=get_next_event_from_iterator(source_iter)
## The client object can be used as a context manager, like this:withget_davclient() asclient:
# Connecting to the caldav servermy_principal=client.principal()
# The principals calendars can be fetched like this:calendars=my_principal.get_calendars()
# replace the URLs by more conventient objectstarget_calendar=replace_calendar_url_by_object(target_calendar, calendars)
calendars_with_title=replace_calendar_urls_in_dictionary_by_object(calendars_with_title, calendars)
calendars_only_busy=replace_calendar_urls_in_dictionary_by_object(calendars_only_busy, calendars)
# delete old entriesdelete_old_entries(target_calendar, 90)
# sync "busy"forcalendar_nameincalendars_only_busy:
sync_calender(calendars_only_busy[calendar_name], target_calendar, calendar_name)
# sync "summary"forcalendar_nameincalendars_with_title:
sync_calender(calendars_with_title[calendar_name], target_calendar, calendar_name, True)
Quite sure it's not perfect, but so far works "good enough". Assumes the CALDAV_USERNAME, CALDAV_PASSWORD and the CALDAV_URL (like CALDAV_URL=https://nextcloud/remote.php/dav) are set as environment variables.
Activity
nextcloud-bot commentedon Sep 14, 2018
GitMate.io thinks possibly related issues are #8698 (need a group or folder for all user), #7340 (Show circle name in details of a shared file (group user)), #866 (Calendar Share Functionality missing), #10347 (Make shares visible to other users), and #3801 (Adding appointment into shared calendar fails).
MorrisJobke commentedon Sep 27, 2018
cc @georgehrke
stefanoco commentedon Dec 10, 2019
georgehrke commentedon Dec 10, 2019
stefanoco commentedon Dec 10, 2019
jfrederickson commentedon Dec 13, 2019
Ideally it'd be possible to do this for calendar links as well. (And to be able to generate links for both full access and free/busy simultaneously.) Google Calendar for example only lets you do one or the other at any given time.
nolens commentedon Jan 23, 2020
I badly need this feature and I have just set a bounty on this.

nolens commentedon Jan 24, 2020
@stefanoco
Would you like add to my bounty on this? I have a couple of freelance programers who I am working with on other projects, they might be able to contribute on short notice....
@georgehrke
Could we setup a group chat somewhere for us and the programers, to discuss scope and for you to give clear directions? Could make life easier, in the end...
brylie commentedon Oct 29, 2020
This would be really important to avoid accidentally publishing event details to a shared calendar. Right now, events seem to default to "when shared, show full event". This may accidentally expose private information when creating an event from a phone or app that doesn't expose the "when shared show" field.
Is it possible to change the default value for "when shared show" field to "when shared, show only busy"?
biva commentedon Mar 2, 2021
47 remaining items
fix(caldav): show confidential event if writable
fix(caldav): show confidential event if writable
fix(caldav): show confidential event if writable
fix(caldav): show confidential event if writable
fix(caldav): show confidential event if writable
fix(caldav): show confidential event if writable
bwurst commentedon Aug 27, 2025
@AndyScherzinger did you possibly close the wrong bug report?
This report is about a demanded new feature for sharing a whole calendar as "only show me busy".
I'd like to have a consumer for my calendar that should never see the details of events but others should.
AndyScherzinger commentedon Aug 27, 2025
Got auto-closed by merging the referenced PR. @st3iny wrong referenced issue?
st3iny commentedon Aug 27, 2025
Yeah, this issue was referenced wrongly.
JlincFM commentedon Mar 2, 2026
Question: To support this, would something as simple as the below work?
kaystrobach commentedon Mar 3, 2026
No
We need different views for different purposes.
So basically share options are the way to go, something to select how detailed event info is shared like all, minimal (title only), just timeslot
JlincFM commentedon Mar 3, 2026
Makes sense. I was trying to think of this in baby steps (small PRs). I.E.:
doppelgrau commentedon Mar 9, 2026
I wrote now a small(?) python script that "solves" this problem for me. It "copies" the entries from some calenders into another one. Either just with predefined Title/Summary or copying the original title/summary after the predefined one (e.g. if some details shouldn't be shared that might be in the notes) but it's ok to get an overall idea what the appointment is about.
Quite sure it's not perfect, but so far works "good enough". Assumes the
CALDAV_USERNAME,CALDAV_PASSWORDand theCALDAV_URL(likeCALDAV_URL=https://nextcloud/remote.php/dav) are set as environment variables.