Object ::caldav::calendars (public)

 ::nx::Object ::caldav::calendars[i]

Defined in packages/xotcl-core/tcl/01-debug-procs.tcl

The class "calendars" implements the interface to the database structures.

Testcases:
No testcase defined.
Source code:
    :object method debug {msg} {
        ns_log Debug(caldav) "[uplevel current proc]: $msg"
    }

    # TODO move get_sync_calendar here
    #
    :public object method format_recurrence {
        {-recurrence_id:integer,0..1}
    } {
        # Return the recurrence specification in form of a formatted
        # ical RRULE.  @param recurrence_id is the unique id of the
        # recurrence item.

        if {$recurrence_id eq ""} {
            return ""
        }
        #ns_log notice "recurrence_id $recurrence_id"
        set recur_rule "RRULE:FREQ="

        ::xo::dc 1row -prepare integer select_recurrence {
            select
                recurrence_id,
                recurrences.interval_type,
                interval_name,
                every_nth_interval,
                days_of_week,
                recur_until
            from
                recurrences,
                recurrence_interval_types
            where recurrence_id= :recurrence_id
            and   recurrences.interval_type = recurrence_interval_types.interval_type
        }

        switch -glob $interval_name {
            day      { append recur_rule "DAILY" }
            week     { append recur_rule "WEEKLY" }
            *month*  { append recur_rule "MONTHLY"}
            year     { append recur_rule "YEARLY"}
        }

        if { $interval_name eq "week"
             && $days_of_week ne ""
         } {
            #DRB: Standard indicates ordinal week days are OK, but Outlook
            #only takes two-letter abbreviation form.

            set week_list [list "SU" "MO" "TU" "WE" "TH" "FR" "SA" "SU"]
            set rec_list [list]
            foreach day [split $days_of_week " "] {
                lappend rec_list [lindex $week_list $day]
            }
            append recur_rule ";BYDAY=" [join $rec_list ,]
        }

        if {$every_nth_interval ne ""} {
            append recur_rule ";INTERVAL=$every_nth_interval"
        }

        if {$recur_until ne ""} {
            set stamp [string range $recur_until 0 18]
            append recur_rule ";UNTIL=" [xo::ical tcl_time_to_utc $stamp]
        }

        #ns_log notice "recur_rule $recur_rule"
        return [::xo::ical reflow_content_line $recur_rule]\r\n
    }


    :public object method get_cal_item_from_uid {
        {-calendar_ids:integer,0..n}
        uid
    } {
        # @return for a uid the cal_item_id(s?)
        # @param uid unique id of an calendar item

        #
        # GN TODO:
        #
        # - document, why and how the or test "e.activity_id = :uid" is
        #   needed this looks like a hack, since the UID can be modified
        #   by a calendar client, we can't assume that this is the same
        #   as some OpenACS id.
        #
        # - when the uid refers to a recurrence item, multiple
        #   cal_item_ids are returned. (a) is this needed (maybe limit
        #   1 is sufficient)? (b) is this handled everywhere
        #   correctly? (c) if needed, name should be change to
        #   get_cal_items_from_uid
        #
        # - HOW ABOUT using activity_id instead of the cal_item_id... such as get_activity_from_uid
        #
        # - probably base on get_calendar_and_cal_item_from_uid
        #
        #
        if {[llength $calendar_ids] > 1} {
            set calclause "in ( [ns_dbquotelist $calendar_ids] )"
        } elseif {[llength $calendar_ids] eq 0} {
            return 0
        } else {
            set calclause "= :calendar_ids"
        }
        set e_clause [expr {[nsf::is integer $uid] ? " or e.activity_id = :uid" : ""}]

        return [::xo::dc list get_cal_item_from_uid [subst {
            select cal_item_id
            from cal_items c, acs_events e
            left outer join cal_uids u on u.on_which_activity = e.activity_id
            where c.cal_item_id = e.event_id
            and ( u.cal_uid = :uid
                  $e_clause
                  )
            and  c.on_which_calendar $calclause
            order by 1 desc
        }]]
    }

    :public object method get_calendar_and_cal_item_from_uid {
        {-calendar_ids:integer,0..n}
        uid
    } {
        # @return for a uid the cal_item_id(s?)
        # @param uid unique id of an calendar item

        #
        # GN TODO:
        #
        # - see above... get_cal_item_from_uid
        #
        # The following query is tricky, since it avoids
        # an error "invalid input syntax for integer" on uids like
        #
        #     23009F17-383F-4FBD-92D4-AB0F27CF7326
        #
        # needs probably work for Oracle.
        #
        return [::xo::dc list_of_lists query_calendar_and_cal_item {
            select c.on_which_calendar, c.cal_item_id
            from acs_events e, cal_items c
            where e.activity_id in
            (
             select CASE WHEN :uid !~ '^[0-9]+$' THEN NULL ELSE :uid ::text::integer END
             union (select on_which_activity from cal_uids where cal_uid = :uid)
            )
            and c.cal_item_id = e.event_id
            order by 2 desc
            limit 1
        }]

        # set e_clause [expr {[nsf::is integer $uid] ? " or e.activity_id = :uid" : ""}]
        #
        # - we could pass-in a calendar-clause, would save a query in
        #   the PUT case
        #if {[llength $calendar_ids] > 1} {
        #    set calclause "in ( [ns_dbquotelist $calendar_ids] )"
        #} elseif {[llength $calendar_ids] eq 0} {
        #    return 0
        #} else {
        #    set calclause "= :calendar_ids"
        #}

        # return [::xo::dc list query_calendar_and_cal_item [subst {
        #     select c.on_which_calendar, cal_item_id
        #     from cal_items c, acs_events e
        #     left outer join cal_uids u on u.on_which_activity = e.activity_id
        #     where c.cal_item_id = e.event_id
        #     and ( u.cal_uid = :uid $e_clause )
        #     and  c.on_which_calendar $calclause
        #     order by 2 desc}]]

    }


    :public object method alwaysQueriedCalendars {
        {-with_sync_calendar:boolean true}
        user_id:integer
    } {
        #
        # @return the calendar_ids, which should be always returned
        #
        lappend calendar_ids {*}[::caldav::get_public_calendars]
        if {$with_sync_calendar} {
            lappend calendar_ids [::caldav::get_sync_calendar -user_id $user_id]
        }
        return $calendar_ids
    }

    :public object method alwaysQueriedClause {
        user_id:integer
    } {
        #
        # @return SQL clause which is always queried
        #
        set calendar_ids [:alwaysQueriedCalendars $user_id]
        if {[llength $calendar_ids] > 0} {
            set values [::xo::db::list_to_values $calendar_ids integer]
            set result [list "select calendar_id from $values as values(calendar_id)"]
        } else {
            set result {}
        }
        return $result
    }

    :public object method communityCalendarClause {
        user_id:integer
    } {
        #
        # Get calendars from communities, when DotLRN is active.
        #
        if {[info commands ::dotlrn_calendar::my_package_key] ne ""} {
            set result [list "
                WITH communities AS (
                                     select distinct dcc.community_id
                                     from dotlrn_communities_core dcc
                                     inner join dotlrn_member_rels_approved dma
                                     on dcc.community_id = dma.community_id
                                     and dma.user_id = $user_id
                                     and dcc.archived_p = 'f'
                                     )
                select calendar_id
                from communities m, calendars c
                join dotlrn_community_applets a on (a.package_id = c.package_id)
                join dotlrn_applets ap on (ap.applet_id = a.applet_id) where
                ap.package_key = 'dotlrn-calendar' and
                a.community_id = m.community_id
            "]
        } else {
            set result {}
        }
        return $result
    }

    :public object method calendar_clause {
        {-calendar_ids:integer,0..n ""}
        {-user_id:integer}
        {-attr c.on_which_calendar}
    } {
        #
        # When calendar_ids are empty, user_id has to be specified
        #

        if {$calendar_ids eq ""} {
            lappend clauses  {*}[:communityCalendarClause $user_id]  {*}[:alwaysQueriedClause $user_id]
            set clause [subst { and $attr in ([join $clauses " union "]) }]
        } elseif {[llength $calendar_ids] == 1} {
            set clause [subst {and $attr = :calendar_ids}]
        } else {
            set clause [subst {and $attr in ( [ns_dbquotelist $calendar_ids] )}]
        }
        :debug calendar_clause=$clause-calendar_ids=$calendar_ids
        return $clause
    }


    #
    # API for selecting calendar items
    #
    :public object method get_calitems {
        {-user_id:integer ""}
        {-start_date ""}
        {-end_date ""}
        {-calendar_ids:integer,0..n ""}
    } {
        #
        # Get feed of calendar items for a given user.
        #
        # @return list set of calendar item objects

        :debug "get_calitems [current args]"

        if {$start_date ne "" && $end_date ne ""} {
            set time_limitation_clause [subst { and start_date between
                to_timestamp('$start_date','YYYY-MM-DD HH24:MI:SS')
                and to_timestamp('$end_date', 'YYYY-MM-DD HH24:MI:SS')
            }]
        } else {
            set time_limitation_clause ""
        }

        set eventlist {}
        set recurrences {}

        #
        # Note that we can have items without a entry in cal_uids for
        # these we will use the activity_id as uid calendars of
        # communities, personal calendars, and public calendars in the
        # same package as the personal calendar-
        #
        foreach item [::xo::dc list_of_lists cal_items [subst {
            select md5(last_modified::text) as etag,
            coalesce(cal_uid, e.activity_id::varchar),
            ical_vars,
            on_which_calendar,
            c.item_type_id,
            to_char(start_date, 'YYYY-MM-DD HH24:MI:SS'),
            to_char(end_date, 'YYYY-MM-DD HH24:MI:SS'),
            coalesce(e.name, a.name),
            coalesce(e.description, a.description),
            c.cal_item_id,
            recurrence_id,
            creation_date,
            last_modified
            from
            acs_objects ao, acs_events e
            left outer join cal_uids u on u.on_which_activity = e.activity_id,
            acs_activities a, timespans s,
            time_intervals t, cal_items c
            where e.event_id = ao.object_id
            and a.activity_id = e.activity_id
            and c.cal_item_id = e.event_id
            and e.timespan_id = s.timespan_id
            and s.interval_id = t.interval_id
            $time_limitation_clause
            [:calendar_clause -calendar_ids $calendar_ids -user_id $user_id]
            order by start_date asc
        }]] {

            lassign $item  etag cal_uid ical_vars calendar_id item_type  start_date end_date name description  cal_item_id recurrence_id creation_date last_modified

            #ns_log notice "get_calitems: item $cal_item_id calendar $calendar_id"  "we got an recurrence <$recurrence_id>"

            if {$recurrence_id ne "" && $recurrence_id in $recurrences} {
                #
                # Don't report calendar items with recurrence multiple
                # times.
                #
                continue
            }
            set caldavItem [::caldav::calitem new  -uid $cal_uid  -ical_vars $ical_vars  -etag $etag  -creation_date $creation_date  -last_modified $last_modified  -dtstart $start_date  -is_day_item [dt_no_time_p -start_time $start_date -end_time $end_date]  -formatted_recurrences [:format_recurrence -recurrence_id $recurrence_id]  -dtend $end_date  -summary $name  -description $description  ]

            $caldavItem destroy_on_cleanup
            lappend eventlist $caldavItem
            lappend recurrences $recurrence_id
        }
        return $eventlist
    }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: