Пример #1
0
class EventView(BrowserView):
    """ Event View """

    implements(IEventView)

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.database = IEventDatabaseProvider(context)
        self.portal_state = getMultiAdapter(
            (self.context, self.request),
            name=u'plone_portal_state'
            )
        self.navigation_root = self.portal_state.navigation_root()
        self.db_org_id = getattr(aq_base(self.navigation_root), 'dbOrgId', 0)
        self.params = param_utils.getQueryParams(request)
        self.eid = self.params['eid']

    def getEvent(self):
        """ find an event by eid """

        return self.database.getEvent(self.eid)

    def getEventDates(self):
        """
            Return a display list of dates.
        """

        return getEventDateRep(self.database.getEventDates(self.eid))

    def displayTime(self, event):
        """ start/end time for display; None if all-day """

        begins = event['begins']
        ends = event['ends']

        if begins == ends:
            if begins == '12:00 AM':
                return None
            return begins
        if ends == '12:00 AM':
            return begins
        return u"%s–%s" % (begins, ends)

    def needOrg(self, oid):
        """ do we need to show organizational details? """

        # Yes, unless oid of event matches that from nav root
        return self.db_org_id != oid

    def getOrg(self, oid):
        """ return a dict for the organization """

        return self.database.getOrgData(oid)

    def getParams(self):
        """ get the useful params as a dict """

        return self.params
Пример #2
0
 def __init__(self, context, request):
     self.context = context
     self.request = request
     self.database = IEventDatabaseProvider(context)
     self.portal_state = getMultiAdapter(
         (self.context, self.request),
         name=u'plone_portal_state'
         )
     self.navigation_root = self.portal_state.navigation_root()
     self.db_org_id = getattr(aq_base(self.navigation_root), 'dbOrgId', 0)
     self.params = param_utils.getQueryParams(request)
     self.eid = self.params['eid']
Пример #3
0
 def __init__(self, context, request):
     assert(INavigationRoot.providedBy(context))
     super(EventEditForm, self).__init__(context, request)
     self.database = IEventDatabaseProvider(context)
     # get eid from 'eid' or 'form.widgets.eid'
     self.eid = int(
         request.form.get('eid',
             request.form.get('form.widgets.eid', '0').replace(',', '')
             )
         )
     self.pdtcal = parsedatetime.Calendar()
     request['disable_border'] = 1
     request['disable_plone.rightcolumn'] = 1
Пример #4
0
    def __init__(self, context, request):
        self.editing = False
        self.context = context
        self.request = request
        self.database = IEventDatabaseProvider(context)
        self.portal_calendar = getToolByName(context, 'portal_calendar')
        self.portal_state = getMultiAdapter((self.context, self.request), name=u'plone_portal_state')
        self.navigation_root = self.portal_state.navigation_root()
        # get db_org_id from the nav root or set to 0
        self.db_org_id = getattr(aq_base(self.navigation_root), 'dbOrgId', 0)
        # get dbOrgList from anywhere in aq chain
        self.db_org_list = param_utils.strToIntList(
            aq_get(self.navigation_root, 'dbOrgList', '')
            )
        if not self.db_org_list and self.db_org_id:
            self.db_org_list = [self.db_org_id]
        self.context_state = getMultiAdapter((self.context, self.request), name=u'plone_context_state')
        self.today = date.today()

        # get params from request
        vals = param_utils.getQueryParams(request)
        # get params from nav root
        svals = param_utils.getSiteParams(self.navigation_root)
        self.site_params = svals
        # consolidate with site params winning collisions
        param_utils.consolidateParams(vals, svals)

        param_orgs = vals.get('org')
        if param_orgs and not self.db_org_list:
            self.db_org_list = param_orgs
            vals['public'] = 'y'
            self.site_params['public'] = 'y'

        # If no org set, always show public, community
        if not self.db_org_list:
            vals['public'] = 'y'
            vals['common'] = 'y'
            # so they don't show up on URLs:
            self.site_params['public'] = 'y'
            self.site_params['common'] = 'y'

        self.params = vals
Пример #5
0
class EventQueryView(BrowserView):
    """
    EventQuery browser view
    """
    implements(IEventQueryView)

    def __init__(self, context, request):
        self.editing = False
        self.context = context
        self.request = request
        self.database = IEventDatabaseProvider(context)
        self.portal_calendar = getToolByName(context, 'portal_calendar')
        self.portal_state = getMultiAdapter((self.context, self.request), name=u'plone_portal_state')
        self.navigation_root = self.portal_state.navigation_root()
        # get db_org_id from the nav root or set to 0
        self.db_org_id = getattr(aq_base(self.navigation_root), 'dbOrgId', 0)
        # get dbOrgList from anywhere in aq chain
        self.db_org_list = param_utils.strToIntList(
            aq_get(self.navigation_root, 'dbOrgList', '')
            )
        if not self.db_org_list and self.db_org_id:
            self.db_org_list = [self.db_org_id]
        self.context_state = getMultiAdapter((self.context, self.request), name=u'plone_context_state')
        self.today = date.today()

        # get params from request
        vals = param_utils.getQueryParams(request)
        # get params from nav root
        svals = param_utils.getSiteParams(self.navigation_root)
        self.site_params = svals
        # consolidate with site params winning collisions
        param_utils.consolidateParams(vals, svals)

        param_orgs = vals.get('org')
        if param_orgs and not self.db_org_list:
            self.db_org_list = param_orgs
            vals['public'] = 'y'
            self.site_params['public'] = 'y'

        # If no org set, always show public, community
        if not self.db_org_list:
            vals['public'] = 'y'
            vals['common'] = 'y'
            # so they don't show up on URLs:
            self.site_params['public'] = 'y'
            self.site_params['common'] = 'y'

        self.params = vals

    @memoize
    def getOrgData(self):
        """
        Returns organization's data as a dict
        """

        return self.database.getOrgData(self.db_org_id)

    def eventsByDateRange(self, start, end):
        """
        Returns a sequence of Events with
        dates between start and end.
        Also, optionally, selects by several criteria
        """

        return self.database.eventsByDateRange(
            start, end, self.db_org_list, **self.params
            )

    def eventsByDay(self, start, end):
        """
        Returns a day-keyed dictionary of days between start and end with events.
        Each day in the sequence is returned as a event list sorted by startTime.
        Also, optionally, selects by several criteria
        """
        days = {}
        query = self.eventsByDateRange(start, end)
        # get the dates, taking recurrence into account
        for result in query:
            recurs = result.get('recurs', 'daily')
            estart = result['start']
            ldate = min(end, result['end'])
            if recurs == 'weekly':
                dates = caldate.weekly(start, ldate, estart)
            elif recurs == 'biweekly':
                dates = caldate.biweekly(start, ldate, estart)
            elif recurs == 'monthly':
                dates = caldate.monthly(start, ldate, estart)
            else:  # daily
                dates = caldate.daily(start, ldate, estart)
            for d in dates:
                days.setdefault(d, []).append(result)

        return days

    def getEventsForMonthDates(self, month_dates):
        """
            Take a structured month list of week lists of days
            and fill it in with each day being a dict with keys:
                day - timedate date
                events - a sequence of events in startTime order
                today - True if day is today
            Each event is a dictionary of event attributes
        """

        today = self.today

        start = month_dates[0][0]
        end = month_dates[-1][-1]
        events = self.eventsByDay(start, end)

        emonth = []
        my_month = month_dates[1][1].month
        for week in month_dates:
            thisweek = []
            for day in week:
                thisweek.append({
                    'day': day.day,
                    'events': events.get(day, []),
                    'today': day == today,
                    'klass': (day.month != my_month) and 'omonth' or '',
                    })
            emonth.append(thisweek)

        return emonth

    def getEventMonth(self, target):
        """
            returns a sequence of weeks, each week being a sequence of days;
            return is in getEventsForMonthDates format
        """

        cal = calendar.Calendar()
        cal.firstweekday = self.portal_calendar.getFirstWeekDay()
        month_dates = cal.monthdatescalendar(target.year, target.month)
        return self.getEventsForMonthDates(month_dates)

    def getEventWeek(self, target):
        """
            returns a sequence of weeks, each week being a sequence of days;
            return is in getEventsForMonthDates format
        """

        month_dates = [caldate.weekDatesCalendar(target)]
        return self.getEventsForMonthDates(month_dates)

    def getEventDay(self, target):
        """
            returns a sequence of weeks, each week being a sequence of days;
            return is in getEventsForMonthDates format
        """

        month_dates = [[target]]
        return self.getEventsForMonthDates(month_dates)

    @memoize
    def getWeekdays(self):
        """Returns a list of Messages for the weekday names."""
        weekdays = list(calendar.day_name)
        weekdays.insert(0, weekdays.pop())
        return weekdays

    def getParams(self):
        """ get params """

        return self.params

    @memoize
    def eventMonth(self):
        """ get events in a month data structure, based on params """

        target = self.params.get('date', self.today)
        mode = self.params.get('mode', 'month')
        if mode == 'day':
            return self.getEventDay(target)
        elif mode == 'week':
            return self.getEventWeek(target)
        else:
            return self.getEventMonth(target)

    @memoize
    def eventList(self):
        """ get events in a simple list, based on params.
            list format [(date, eventdict),...] """

        target = self.params.get('date', self.today)
        mode = self.params.get('mode', 'month')
        if mode == 'day':
            edict = self.eventsByDay(target, target)
        elif mode == 'week':
            edict = self.eventsByDay(caldate.startOfWeek(target), caldate.endOfWeek(target))
        elif mode == 'upcoming':
            end = self.today + timedelta(self.params.get('days', 30))
            edict = self.eventsByDay(self.today, end)
        else:
            edict = self.eventsByDay(caldate.startOfMonth(target), caldate.endOfMonth(target))
        keys = edict.keys()
        keys.sort()
        elist = []
        for key in keys:
            elist.append([key, edict[key]])
        return elist

    def eventDayList(self, max=0):
        """ return upcoming events as list of day lists.
            Format is [[date, [eventdict,...]]...] """

        def mediumFormatDate(d):
            return d.strftime("%A, %x")

        self.params['mode'] = 'upcoming'
        events = self.eventList()
        day = []
        rez = []
        last_date = date(1900, 1, 1)
        found = 0
        for e in events:
            sdate = e[0]
            if sdate != last_date:
                if day:
                    rez.append([mediumFormatDate(last_date), day])
                    day = []
                last_date = sdate
            day += e[1]
            found += len(day)
            if found >= max:
                break
        if day:
            rez.append([mediumFormatDate(last_date), day])
        return rez

    def myUrl(self, **overrides):
        """
            Assemble a URL that will reproduce the
            current calendar with optional overrides.
            override with a None value to remove an
            item.
        """

        params = self.params.copy()
        # consolidate overrides
        for s in overrides:
            oval = overrides[s]
            if oval is None:
                # delete it from params
                try:
                    del params[s]
                except KeyError:
                    pass
            else:
                params[s] = overrides[s]
        # remove keys present in site params
        for s in params.keys():
            if s in self.site_params:
                del params[s]

        # generate query params when the setting isn't the default
        val = params.get('date')
        if val and val != self.today:
            s = "date=%s;" % val.isoformat()
        else:
            s = ''
        val = params.get('mode', 'month')
        if val != 'month':
            s = "%smode=%s;" % (s, val)
        val = params.get('gcid')
        if val:
            s = "%sgcid=%s;" % (s, val)
        val = params.get('public', 'b')
        if val != 'b':
            s = "%spublic=%s;" % (s, val)
        val = params.get('common', 'b')
        if val != 'b':
            s = "%scommon=%s;" % (s, val)
        val = params.get('udf1', 'n')
        if val != 'n':
            s = "%sudf1=%s;" % (s, val)
        val = params.get('udf2', 'n')
        if val != 'n':
            s = "%sudf2=%s;" % (s, val)
        val = params.get('org', self.db_org_id)
        if val != self.db_org_id:
            s = "%sorg=%s;" % (s, ','.join([str(int(i)) for i in val]))

        if s:
            s = "?%s" % s
        return "%s%s" % (self.context_state.current_base_url(), s)

    def monthUrl(self):
        """ url for month-mode calendar """
        return self.myUrl(mode='month')

    def weekUrl(self):
        """ url for week-mode calendar """
        return self.myUrl(mode='week')

    def dayUrl(self):
        """ url for day-mode calendar """
        return self.myUrl(mode='day')

    def nextUrl(self):
        """ url for next calendar """
        mode = self.params.get('mode', 'month')
        cdate = self.params.get('date', date.today())
        if mode == 'day':
            cdate += timedelta(1)
        elif mode == 'week':
            cdate += timedelta(7)
        elif mode == 'month':
            cdate = caldate.startOfNextMonth(cdate)
        return self.myUrl(date=cdate)

    def todayUrl(self):
        """ url to get today's calendar """
        return self.myUrl(date=self.today)

    def prevUrl(self):
        """ url for previous calendar """
        mode = self.params.get('mode', 'month')
        cdate = self.params.get('date', self.today)
        if mode == 'day':
            cdate -= timedelta(1)
        elif mode == 'week':
            cdate -= timedelta(7)
        elif mode == 'month':
            cdate = caldate.startOfMonth(cdate) - timedelta(1)
        return self.myUrl(date=cdate)

    def getMode(self):
        """ return the current display mode: month, week, day """

        return self.params.get('mode', 'month')

    def getMonthYear(self):
        """ return the displayed month and year, suitable for presentation """

        return self.params.get('date', self.today).strftime("%B, %Y")

    def getFullDate(self):
        """ return the full date of the current display, suitable for presentation """

        return self.params.get('date', self.today).strftime("%B %d, %Y").replace(' 0', ' ')

    def getCats(self, oid=0, include_all=True):
        """ return a list of categories in alpha order unless suppressed """

        current_gcid = self.params.get('gcid', -1)
        if include_all:
            res = [{
                'title': u'All',
                'url': self.allCatsUrl(),
                'current': current_gcid == -1
                }]
        else:
            res = []
        for item in self.database.getCats(oid=oid):
            res.append({
                'title': decodeString(item.title),
                'gcid': item.gcid,
                'url': self.myUrl(gcid=item.gcid),
                'current': item.gcid == current_gcid,
                })
        return res

    @memoize
    def getDisplayCats(self):
        """ return an appropriate list of cats for display """

        if self.params.get('nocat-display'):
            return []
        db_org_id = self.db_org_id
        if db_org_id == 0:
            return self.getCats(oid=0)
        cat_options = getattr(self.navigation_root, 'catOptions', [])
        if 'useOrgCats' in cat_options:
            return self.getCats(oid=db_org_id)
        if 'useMajorCats' in cat_options:
            return self.getCats(oid=0)
        return []

    def allCatsUrl(self):
        """ url with no gcid """
        return self.myUrl(gcid=None)

    def allCatsCurrent(self):
        """ returns true if there's no gcid in the params """
        return self.params.get('gcid', None) is None

    @memoize
    def showEventUrl(self):
        """ base url to display individual events """

        return "%s/showEvent?eid=" % self.portal_state.navigation_root_url()

    @memoize
    def useAcronyms(self):
        """ should we display acronyms? """

        return not (self.db_org_id or self.db_org_list) and self.getMode() != 'day'

    def setParam(self, **kwa):
        """ set params directly, typically from a template """

        for key, value in kwa.items():
            val = param_utils.sanitizeParam(key, value)
            if val is not None:
                self.params[key] = val
                # also set site_params so that the flag
                # won't show in the query params returned
                # by myURL(). This is based on the assumption
                # that this method is called from a template.
                self.site_params[key] = val

    def editMode(self):
        """ are we in edit mode? """

        return self.editing

    @ram.cache(lambda *args: time() // 300)
    def orgList(self):
        """
            return a list of current organizations
        """

        print "Generating orgList"
        base_url = self.context_state.current_base_url()
        org_list = self.database.currentOrgs()
        ol_len_third = len(org_list) / 3 + 1
        rez = [[], [], []]
        count = 0
        for o in org_list:
            if o.alt_cal_url:
                url = o.alt_cal_url
            else:
                url = "%s?org=%d" % (base_url, o.oid)
            rez[count / ol_len_third].append({
                'url': url,
                'orgname': o.orgname,
                'acronym': o.acronym,
                })
            count += 1
        return rez

    @memoize
    def showOrgList(self):
        """
            returns True if we should display org list
        """
        # print self.db_org_id, self.db_org_list
        return not (self.db_org_id or self.db_org_list)

    @memoize
    def orgForDisplay(self):
        """
            returns current org --
            if there is one, and if we need a special
            display.
        """

        if len(self.db_org_list) == 1:
            return self.database.getOrg(self.db_org_list[0])
        return None
Пример #6
0
 def __init__(self, context, request):
     assert(INavigationRoot.providedBy(context))
     super(EventOrgEditForm, self).__init__(context, request)
     self.database = IEventDatabaseProvider(context)
     request['disable_border'] = 1
     request['disable_plone.rightcolumn'] = 1
Пример #7
0
class EventOrgEditForm(form.SchemaForm):
    """ Define Form handling
    """

    schema = IEventOrgSchema
    ignoreContext = False

    label = u"Calendar settings"
    description = u"Community Calendar settings for this organization."
    # form_name = u"Calendar settings"

    # attributes we'll be setting and getting from the
    # context. The rest will come from the database.
    context_attributes = (
        'catOptions',
        'defaultMajorCats',
        'udf1_name',
        'udf2_name',
        )

    # attributes we'll get from the database view
    database_attributes = (
        'name',
        'description',
        'acronym',
        'url',
        'alt_cal_url',
        'contact',
        'email',
        'phone',
        'ccal_link',
        )

    def __init__(self, context, request):
        assert(INavigationRoot.providedBy(context))
        super(EventOrgEditForm, self).__init__(context, request)
        self.database = IEventDatabaseProvider(context)
        request['disable_border'] = 1
        request['disable_plone.rightcolumn'] = 1
        # self.evq_view = getMultiAdapter((self.context, self.request), name=u'eventquery_view')

    def getContent(self):
        """
        fill and return a content object
        """

        obj = OrgContext()
        # orgCatSource will need to be able to get at the database
        obj._database = self.database

        for key in EventOrgEditForm.context_attributes:
            value = getattr(self.context, key, '')
            setattr(obj, key, value)

        if self.database.db_org_id:
            org_data = self.database.getOrgData()
            for key in EventOrgEditForm.database_attributes:
                value = org_data.get(key)
                setattr(obj, key, value)
            obj.org_categories = [c.title for c in self.database.getOrgCats()]
        else:
            obj.name = getattr(self.context, 'title', u"Organization Name")
            obj.description = getattr(self.context, 'description', u"Organization Description")

        return obj

    @button.buttonAndHandler(u'Save')
    def handleApply(self, action):
        data, errors = self.extractData()

        # get write access to the database
        portal_state = getMultiAdapter(
            (self.context, self.request),
            name=u'plone_portal_state'
            )
        navigation_root = portal_state.navigation_root()
        writer = IEventDatabaseWriteProvider(navigation_root)

        if errors:
            self.status = self.formErrorsMessage
            return

        for key in EventOrgEditForm.context_attributes:
            value = data.get(key)
            setattr(self.context, key, value)

        org_data = {}
        for key in EventOrgEditForm.database_attributes:
            org_data[key] = data.get(key)
        if writer.db_org_id == 0:
            db_org_id = writer.insertOrg(**org_data)
            setattr(navigation_root, 'dbOrgId', db_org_id)
        else:
            writer.updateOrgData(**org_data)

        writer.updateOrgCats(data.get('org_categories', []))

        messages = IStatusMessage(self.request)
        messages.add(u"Organization event settings updated", type=u"info")

        self.request.response.redirect("caledit")

    @button.buttonAndHandler(u"Cancel")
    def handleCancel(self, action):
        """User cancelled. Redirect back to the front page.
        """

        self.request.response.redirect("caledit")
Пример #8
0
class EventEditForm(form.SchemaForm):
    """ Define Form handling
    """

    schema = IEventEditForm
    ignoreContext = False

    # attributes we'll get from the database view
    database_attributes = (
        'eid',
        'title',
        'description',
        'location',
        'eventUrl',
        'eventContact',
        'eventEmail',
        'eventPhone',
        'begins',
        'ends',
        )

    def __init__(self, context, request):
        assert(INavigationRoot.providedBy(context))
        super(EventEditForm, self).__init__(context, request)
        self.database = IEventDatabaseProvider(context)
        # get eid from 'eid' or 'form.widgets.eid'
        self.eid = int(
            request.form.get('eid',
                request.form.get('form.widgets.eid', '0').replace(',', '')
                )
            )
        self.pdtcal = parsedatetime.Calendar()
        request['disable_border'] = 1
        request['disable_plone.rightcolumn'] = 1

    def updateWidgets(self):
        super(EventEditForm, self).updateWidgets()
        self.widgets['eid'].mode = z3c.form.interfaces.HIDDEN_MODE

    def updateActions(self):
            super(EventEditForm, self).updateActions()

            delete_action = self.actions.get('handleDelete')
            if delete_action:
                delete_action.onclick = u"return confirm('Delete this event?')"

    def getContent(self):
        """
        fill and return a content object
        """

        def strToDate(s):
            yr, mo, day = s.split('-')
            return date(int(yr), int(mo), int(day))

        def findRecurs(dates):
            last_delta = None
            starts = [d.start for d in dates]
            prev = strToDate(starts[0])
            for start in starts[1:]:
                dt = strToDate(start)
                delta = dt - prev
                if last_delta and delta != last_delta:
                    return None
                prev = dt
                last_delta = delta
            if delta.days == 1:
                recurs = "daily"
            elif delta.days == 7:
                recurs = "weekly"
            elif delta.days == 7:
                recurs = "biweekly"
            else:
                return None

            # we need to return an object with start, end, recurs
            # attributes
            obj = Recurrence()
            obj.start = starts[0]
            obj.end = starts[-1]
            obj.recurs = recurs
            return obj

        obj = EventContext()
        obj._database = self.database

        eid = self.eid
        if eid:
            event_data = self.database.getEvent(eid)
            for key in EventEditForm.database_attributes:
                value = event_data.get(key)
                setattr(obj, key, value)
            for key in ('public', 'free', 'community'):
                setattr(obj, key, event_data[key] == "Y")

            cats = [c.gcid for c in self.database.getEventCats(eid)]
            my_cats = [c.gcid for c in self.database.getOrgCats()]
            org_cats = []
            major_cats = []
            for gcid in cats:
                if gcid in my_cats:
                    org_cats.append(gcid)
                else:
                    major_cats.append(gcid)
            obj.majorCats = major_cats
            obj.orgCats = org_cats

            dates = self.database.getEventDates(eid)

            # check to see if this is an old-style date list
            # that happens to recur regularly
            if len(dates) > 1:
                recurs = findRecurs(dates)
                if recurs:
                    # we can normalize it to start, end, recurs
                    dates = [recurs]

            if len(dates) == 1:
                # simple scheduling
                obj.start = strToDate(dates[0].start)
                obj.end = strToDate(dates[0].end)
                obj.recurs = dates[0].recurs
            else:
                # we are irregularly scheduled
                obj.start = date.today()
                obj.end = date.today()
                obj.recurs = 'irregular'
                if len(dates):
                    wkdates = []
                    for d in dates:
                        yr, mo, dy = d.start.split('-')
                        wkdates.append("/".join((mo, dy, yr[2:])))
                    obj.dates = ", ".join(wkdates)
        else:
            obj.start = date.today()
            obj.end = date.today()
            portal_state = getMultiAdapter(
                (self.context, self.request), name=u'plone_portal_state')
            navigation_root = portal_state.navigation_root()
            obj.majorCats = getattr(navigation_root, 'defaultMajorCats', [])

        return obj

    def _getWriter(self):
        """
            return a database writer
        """

        portal_state = getMultiAdapter(
            (self.context, self.request),
            name=u'plone_portal_state'
            )
        navigation_root = portal_state.navigation_root()
        return IEventDatabaseWriteProvider(navigation_root)

    @button.buttonAndHandler(u'Save Event')
    def handleApply(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return

        # get write access to the database
        writer = self._getWriter()
        form = self.request.form
        portal_state = getMultiAdapter(
            (self.context, self.request),
            name=u'plone_portal_state'
            )
        member = portal_state.member()

        eid = data['eid']

        event_data = {}
        for key in EventEditForm.database_attributes:
            if key != 'eid':
                if key == 'begins':
                    # ##:## time from struct_time
                    event_data['startTime'] = struct_time2str(form['begins_time'])
                elif key == 'ends':
                    event_data['endTime'] = struct_time2str(form['ends_time'])
                else:
                    event_data[key] = data.get(key)
        for key in ('public', 'free', 'community'):
            event_data[key] = data.get(key) and "Y" or "N"

        if eid:
            writer.updateEvent(eid, member, **event_data)
            writer.deleteEventCats(eid)
            writer.deleteEventDates(eid)
        else:
            eid = writer.eventInsert(member, **event_data)

        writer.evCatsInsert(eid, list(data['orgCats'].union(data['majorCats'])))

        if data['recurs'] == 'irregular':
            # irregular scheduling; save a list of dates
            writer.evDatesInsert(
                eid,
                [(dt, dt, u"daily") for dt in form['date_list']]
                )
        else:
            # regular scheduling
            writer.evDatesInsert(eid, ((data['start'], data['end'], data['recurs']), ))

        messages = IStatusMessage(self.request)
        messages.add(u"Event saved", type=u"info")

        self.request.response.redirect("@@caledit")

    @button.buttonAndHandler(u"Delete Event",
        name="handleDelete",
        condition=lambda form: form.eid != 0)
    def handleDelete(self, action):
        """
            Delete this event.
        """

        eid = self.eid
        assert(eid != 0)

        writer = self._getWriter()
        writer.deleteEventCats(eid)
        writer.deleteEventDates(eid)
        writer.deleteEvent(eid)

        messages = IStatusMessage(self.request)
        messages.add(u"Event deleted", type=u"info")

        self.request.response.redirect("caledit")

    @button.buttonAndHandler(u"Cancel Edits")
    def handleCancel(self, action):
        """User cancelled. Redirect back to the front page.
        """

        self.request.response.redirect("caledit")