caldav::CalDAV instproc PUT (public)

 <instance of caldav::CalDAV[i]> PUT

Defined in /var/www/openacs.org/packages/caldav/tcl/caldav-procs.tcl

UPDATE (SAVE?) a single calendar item denoted by a uid of a calendar item.

Testcases:
Thunderbird_add_event, macOS_add_location, macOS_add_event
Source code:
set content [:getcontent {If-Match ""}]
set ifmatch [ns_set iget [ns_conn headers] If-Match "*"]

#
# The request URI has to end with UID.ics, but we get the
# actual UID from the ical UID field of the parsed content.
#
if {![string match *.ics ${:uri}]} {
    return [:request_error "Trying to PUT on a calendar that does not end with *.ics: ${:uri}"]
}

try {
    set sync_calendar_id [::caldav::get_sync_calendar -user_id ${:user_id}]
} on error {errorMsg} {
    return [:request_error "no private calendar found for ${:user_id}"]
}

set items [calendars parse $content]
:debug "caldav parser returned items <$items>"

foreach item $items {
    set uid [$item cget -uid]
    :debug [$item serialize]

    if {$ifmatch eq "*"} {
        #
        # Create new entry
        #
        :debug "add a new entry"
        set calendar_id $sync_calendar_id
        #
        # We should probably check, whether we can really
        # write on the calendar in the general case, but here,
        # we know, the sync calendar is always writable for the
        # current user.
        #
        # - GN TODO: not sure, when mutating the UID is necessary, and
        #   whether adding a suffix with the user_id is the best solution.
        #   So we deactivate this code for now....
        #
        if {0} {
            set user_id ${:user_id}
            if {[::xo::dc get_value -prepare varchar,integer uid_exists {
                select 1 from cal_uids u
                join acs_objects o on (o.object_id = u.on_which_activity)
                where cal_uid = :uid
                and o.creation_user != :user_id
            } 0]} {
                ad_log warning "uid already exists for another user, suffixing ${uid}-${:user_id}"
                $item set uid "${uid}-${:user_id}"
            }
        }
    } else {
        #
        # Update an existing entry
        #
        :debug "update existing entry..."

        lappend clauses  {*}[calendars communityCalendarClause ${:user_id}]  {*}[calendars alwaysQueriedClause ${:user_id}]

        set all_calendar_ids [::xo::dc list read_only_cals [subst {
            select calendar_id from ([join $clauses " union "]) as cals
        }]]

        set cal_infos [calendars get_calendar_and_cal_item_from_uid -calendar_ids $all_calendar_ids $uid]
        :debug "cal_infos for calendar_ids $all_calendar_ids uid $uid -> <$cal_infos>"

        if {$cal_infos ne ""} {
            set cal_info [lindex $cal_infos 0]
            lassign $cal_info calendar_id cal_item_id

            :debug "write check needed? [expr {$calendar_id ne $sync_calendar_id}]"

            if {$calendar_id != $sync_calendar_id} {
                set can_write_p [permission::permission_p -object_id $cal_item_id -privilege write]
                :debug "write check: $can_write_p (calendar_id $calendar_id, sync_calendar_id $sync_calendar_id)"

                if {!$can_write_p} {
                    ns_log warning "CalDAV: user tried to perform a PUT on a read only item item: $cal_item_id user ${:user_id}"
                    if {[string match "*CalDavSynchronizer*" ${:user_agent}]} {
                        #
                        # Outlook synchronizer will continue
                        # hammering if 403 is returned,
                        # therefore try a different status
                        # code.
                        #
                        # GN TODO: please check, what happens
                        # with status code 412 on Outlook,
                        # since 202 probably silently swallows
                        # the update, which never happens.
                        #
                        :debug "CalDav: outlook client encountered"
                        set statusCode 202
                    } else {
                        set statusCode 412
                    }
                    return [:response $statusCode text/plain {}]
                }
            }
        }
    }
    #
    # save the item
    #
    :debug "updating item [$item cget -uid] in calendar $sync_calendar_id"
    :item_update -calendar_id $sync_calendar_id -item $item

    #ns_log notice "CalDAV PUT: [$item serialize]"
    ns_set put [ns_conn outputheaders] ETag [subst {"[:getETagByUID [$item cget -uid]]"}]
    $item destroy
    :response 201 text/plain {}
    return
}
# TODO what happens here
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: