Search in sources :

Example 6 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method doRecurrence.

/* Retrieves the overides for a recurring event and if required,
   * retrieves the instances.
   *
   * The overrides we retrieve are optionally limited by date.
   *
   * The CalDAV spec requires that we retrieve all overrides which fall within
   * the given date range AND all instances in that date range including
   * overriden instances that WOULD have fallen in that range had they not been
   * overriden.
   *
   * Thus we need to search both overrides and instances - unless no date range
   * is given in which case all overrides will appear along with the instances.
   *
   * If the calendars parameter is non-null, as it usually will be for a call
   * from getEvents, we limit the result to instances that appear within that
   * set of calendars. This handles the case of an overriden instance moved to a
   * different calendar, for example the trash.
   */
@SuppressWarnings("unchecked")
private void doRecurrence(final CoreEventInfo cei, final RecurringRetrievalMode recurRetrieval) throws CalFacadeException {
    final BwEvent master = cei.getEvent();
    final Set<String> overrides = new HashSet<>();
    final CurrentAccess ca = cei.getCurrentAccess();
    // Always fetch all overrides
    final Collection<BwEventAnnotation> ovs = dao.eventQuery(BwEventAnnotation.class, null, null, null, master, // overrides
    true, // recurRetrieval);
    null);
    if (ovs != null) {
        for (final BwEventAnnotation override : ovs) {
            final CoreEventInfo ocei = makeOverrideProxy(override, ca);
            cei.addOverride(ocei);
            overrides.add(ocei.getEvent().getRecurrenceId());
        }
    }
    if ((recurRetrieval == null) || (recurRetrieval.mode != Rmode.expanded)) {
        return;
    }
    /* Create a list of all instance date/times before overrides. */
    final int maxYears;
    final int maxInstances;
    maxYears = getAuthprops().getMaxYears();
    maxInstances = getAuthprops().getMaxInstances();
    final RecurPeriods rp = RecurUtil.getPeriods(master, maxYears, maxInstances);
    if (rp.instances.isEmpty()) {
        // No instances for an alleged recurring event.
        return;
    // throw new CalFacadeException(CalFacadeException.noRecurrenceInstances);
    }
    final String stzid = master.getDtstart().getTzid();
    final boolean dateOnly = master.getDtstart().getDateType();
    /* Emit all instances that aren't overridden. */
    final TreeSet<CoreEventInfo> ceis = new TreeSet<>();
    for (final Period p : rp.instances) {
        String dtval = p.getStart().toString();
        if (dateOnly) {
            dtval = dtval.substring(0, 8);
        }
        final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
        if (overrides.contains(rstart.getDate())) {
            // Overrides built separately - skip this instance.
            continue;
        }
        final String recurrenceId = rstart.getDate();
        dtval = p.getEnd().toString();
        if (dateOnly) {
            dtval = dtval.substring(0, 8);
        }
        final BwDateTime rend = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
        final BwRecurrenceInstance inst = new BwRecurrenceInstance(rstart, rend, recurrenceId, master, null);
        final CoreEventInfo instcei = makeInstanceProxy(inst, ca);
        if (instcei != null) {
            // if (debug) {
            // debugMsg("Ev: " + proxy);
            // }
            ceis.add(instcei);
        }
    }
    cei.setInstances(ceis);
}
Also used : BwDateTime(org.bedework.calfacade.BwDateTime) CoreEventInfo(org.bedework.calcorei.CoreEventInfo) Period(net.fortuna.ical4j.model.Period) BwEvent(org.bedework.calfacade.BwEvent) BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) BwEventAnnotation(org.bedework.calfacade.BwEventAnnotation) TreeSet(java.util.TreeSet) CurrentAccess(org.bedework.access.Acl.CurrentAccess) RecurPeriods(org.bedework.icalendar.RecurUtil.RecurPeriods) HashSet(java.util.HashSet)

Example 7 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method updateEvent.

@Override
public UpdateEventResult updateEvent(final EventInfo ei) throws CalFacadeException {
    final BwEvent val = ei.getEvent();
    final Collection<BwEventProxy> overrides = ei.getOverrideProxies();
    final Collection<BwEventProxy> deletedOverrides = ei.getDeletedOverrideProxies(cb.getPrincipalInfo().getPrincipal().getPrincipalRef());
    final UpdateEventResult ue = new UpdateEventResult();
    if (!ac.checkAccess(val, privWrite, true).getAccessAllowed()) {
        // XXX Is this correct?
        try {
            ac.checkAccess(val, privWriteContent, false);
        } catch (final CalFacadeException cfe) {
            throwException(cfe);
        }
    }
    BwEventProxy proxy = null;
    if (val instanceof BwEventProxy) {
        proxy = (BwEventProxy) val;
    }
    final BwCalendar col = getCollection(val.getColPath());
    final boolean shared = col.getPublick() || col.getShared();
    if ((proxy != null) && (proxy.getRef().getOverride())) {
        final BwEventAnnotation ann = proxy.getRef();
        final BwEvent mstr = ann.getMaster();
        if (!proxy.getUid().equals(mstr.getUid())) {
            throwException("org.bedework.cannot.overrideuid");
        }
        if (!proxy.getName().equals(mstr.getName())) {
            throwException("org.bedework.cannot.overridename");
        }
    } else {
        /* The guid must not exist in the same calendar. We assign a guid if
       * one wasn't assigned already. However, the event may have come with a guid
       * (caldav, import, etc) so we need to check here.
       *
       * It also ensures our guid allocation is working OK
       */
        final CollectionInfo collInf = col.getCollectionInfo();
        if (collInf.uniqueKey) {
            String name = calendarGuidExists(val, false, false);
            if (name == null) {
                name = calendarGuidExists(val, true, false);
            }
            if (name != null) {
                throwException(CalFacadeException.duplicateGuid, name);
            }
        }
        /* Similarly for event names which must be unique within a collection
       */
        if (calendarNameExists(val, false, false) || calendarNameExists(val, true, false)) {
            throwException(new CalFacadeDupNameException(val.getName()));
        }
    }
    if (!(val instanceof BwEventProxy)) {
        dao.update(val);
        final Collection<BwDbentity<?>> deleted = val.getDeletedEntities();
        if (deleted != null) {
            for (final BwDbentity ent : deleted) {
                dao.delete(ent);
            }
            deleted.clear();
        }
        if (val.testRecurring()) {
            if (!Util.isEmpty(overrides)) {
                for (final BwEventProxy pxy : overrides) {
                    final BwEventAnnotation ann = pxy.getRef();
                    boolean updated = false;
                    if ((ann.getRecurring() != null) && ann.getRecurring()) {
                        // be safe
                        ann.setRecurring(false);
                        updated = true;
                    }
                    if (ann.getTombstoned() == null) {
                        // be safe
                        ann.setTombstoned(false);
                        updated = true;
                    }
                    if (ann.unsaved()) {
                        dao.save(ann);
                    } else if (updated) {
                        updateProxy(new BwEventProxy(ann));
                    }
                }
            }
            updateRecurrences(ei, ue, overrides, shared);
        }
        if (!val.testRecurring() || (Util.isEmpty(overrides) && Util.isEmpty(deletedOverrides))) {
            notify(SysEvent.SysCode.ENTITY_UPDATED, val, shared);
            indexEntity(ei);
            return ue;
        }
        if (!Util.isEmpty(overrides)) {
            updateOverrides: for (final BwEventProxy pxy : overrides) {
                final BwEventAnnotation ann = pxy.getRef();
                if (ue.deleted != null) {
                    for (final BwRecurrenceInstance ri : ue.deleted) {
                        if (ri.getRecurrenceId().equals(ann.getRecurrenceId())) {
                            continue updateOverrides;
                        }
                    }
                }
                if (ue.added != null) {
                    for (final BwRecurrenceInstance ri : ue.added) {
                        if (ri.getRecurrenceId().equals(ann.getRecurrenceId())) {
                            continue updateOverrides;
                        }
                    }
                }
                // be safe
                ann.setRecurring(false);
                if (ann.getTombstoned() == null) {
                    // be safe
                    ann.setTombstoned(false);
                }
                if (!ann.unsaved()) {
                    updateProxy(new BwEventProxy(ann));
                } else {
                    dao.save(ann);
                    /* See if there is an instance for this override
             */
                    BwRecurrenceInstance ri = dao.getInstance(val, ann.getRecurrenceId());
                    if (ri == null) {
                        final BwDateTime rid = BwDateTime.fromUTC(ann.getRecurrenceId().length() == 8, ann.getRecurrenceId());
                        final Dur dur = new Dur(val.getDuration());
                        final BwDateTime end = rid.addDur(dur);
                        ri = new BwRecurrenceInstance();
                        ri.setDtstart(rid);
                        ri.setDtend(end);
                        ri.setRecurrenceId(rid.getDate());
                        ri.setMaster(val);
                        ri.setOverride(ann);
                        dao.save(ri);
                    } else {
                        ri.setOverride(ann);
                        dao.update(ri);
                    }
                }
                notifyInstanceChange(SysEvent.SysCode.ENTITY_UPDATED, val, shared, ann.getRecurrenceId());
            }
        }
        if (!Util.isEmpty(deletedOverrides)) {
            final Collection<String> rids = new ArrayList<>();
            for (final BwEventProxy pxy : deletedOverrides) {
                rids.add(pxy.getRecurrenceId());
            }
            removeInstances(val, rids, ue, deletedOverrides, shared);
        }
    } else {
        if (proxy.getChangeFlag()) {
            updateProxy(proxy);
        }
    }
    notify(SysEvent.SysCode.ENTITY_UPDATED, val, shared);
    if (proxy != null) {
        if (ei.getRetrievedEvent() == null) {
            warn("No retrieved event for indexer");
        } else {
            final EventInfo rei = ei.getRetrievedEvent();
            rei.addOverride(ei);
            indexEntity(rei);
        }
    } else {
        indexEntity(ei);
    }
    return ue;
}
Also used : Dur(net.fortuna.ical4j.model.Dur) BwDateTime(org.bedework.calfacade.BwDateTime) CoreEventInfo(org.bedework.calcorei.CoreEventInfo) EventInfo(org.bedework.calfacade.svc.EventInfo) CollectionInfo(org.bedework.calfacade.BwCalendar.CollectionInfo) ArrayList(java.util.ArrayList) BwEvent(org.bedework.calfacade.BwEvent) BwCalendar(org.bedework.calfacade.BwCalendar) BwEventProxy(org.bedework.calfacade.BwEventProxy) CalFacadeException(org.bedework.calfacade.exc.CalFacadeException) BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) CalFacadeDupNameException(org.bedework.calfacade.exc.CalFacadeDupNameException) BwEventAnnotation(org.bedework.calfacade.BwEventAnnotation) BwDbentity(org.bedework.calfacade.base.BwDbentity)

Example 8 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method addEvent.

@Override
public UpdateEventResult addEvent(final EventInfo ei, final boolean scheduling, final boolean rollbackOnError) throws CalFacadeException {
    final BwEvent val = ei.getEvent();
    final Collection<BwEventProxy> overrides = ei.getOverrideProxies();
    final long startTime = System.currentTimeMillis();
    RecuridTable recurids = null;
    final UpdateEventResult uer = new UpdateEventResult();
    uer.addedUpdated = true;
    final BwCalendar cal = getEntityCollection(val.getColPath(), privBind, scheduling, false);
    /* Indicate if we want sharing notifications of changes */
    final boolean shared = cal.getPublick() || cal.getShared();
    final CollectionInfo collInf = cal.getCollectionInfo();
    if (!Util.isEmpty(overrides)) {
        if (!val.testRecurring()) {
            throwException(CalFacadeException.overridesForNonRecurring);
        }
        recurids = new RecuridTable(overrides);
    }
    if (val.getUid() == null) {
        throwException(CalFacadeException.noEventGuid);
    }
    if (val.getName() == null) {
        throwException(CalFacadeException.noEventName);
    }
    /* The guid must not exist in the same calendar. We assign a guid if
     * one wasn't assigned already. However, the event may have come with a guid
     * (caldav, import, etc) so we need to check here.
     *
     * It also ensures our guid allocation is working OK
     */
    if (collInf.uniqueKey) {
        String name = calendarGuidExists(val, false, true);
        if (name == null) {
            name = calendarGuidExists(val, true, true);
        }
        if (name != null) {
            throwException(CalFacadeException.duplicateGuid, name);
        }
    }
    /* Similarly for event names which must be unique within a collection.
     * Note that a duplicate name is essentially overwriting an event with a
     * new uid - also disallowed.
     */
    if ((val.getEntityType() != IcalDefs.entityTypeAvailable) && (calendarNameExists(val, false, true) || calendarNameExists(val, true, true))) {
        throwException(CalFacadeException.duplicateName, val.getName());
    }
    setupDependentEntities(val);
    /* Remove any tombstoned event in the collection with same uid */
    deleteTombstoned(val.getColPath(), val.getUid());
    /* If it's a recurring event see what we can do to optimize searching
     * and retrieval
     */
    if ((val instanceof BwEventAnnotation) || !val.getRecurring()) {
        dao.save(val);
        if (!getForRestore()) {
            notify(SysEvent.SysCode.ENTITY_ADDED, val, shared);
        }
        stat(StatsEvent.createTime, startTime);
        indexEntity(ei);
        return uer;
    }
    /* Get all the times for this event. - this could be a problem. Need to
       limit the number. Should we do this in chunks, stepping through the
       whole period?
     */
    final RecurPeriods rp = RecurUtil.getPeriods(val, getAuthprops().getMaxYears(), getAuthprops().getMaxInstances());
    if (rp.instances.isEmpty()) {
        // No instances for an alleged recurring event.
        if (rollbackOnError) {
            throwException(CalFacadeException.noRecurrenceInstances, val.getUid());
        }
        uer.addedUpdated = false;
        uer.errorCode = CalFacadeException.noRecurrenceInstances;
        stat(StatsEvent.createTime, startTime);
        indexEntity(ei);
        return uer;
    }
    /* We can save the master at this point */
    dao.save(val);
    final String stzid = val.getDtstart().getTzid();
    final TimeZone stz = null;
    /*    try {
      if (stzid != null) {
        stz = Timezones.getTz(stzid);
      }
      val.setLatestDate(Timezones.getUtc(rp.rangeEnd.toString(),
                                         stzid));
    } catch (Throwable t) {
      throwException(new CalFacadeException(t));
    } */
    int maxInstances = getAuthprops().getMaxInstances();
    final boolean dateOnly = val.getDtstart().getDateType();
    /* There appears to be a bug in ical4j in which the first instance gets
     * duplicated. Rather than change that code and run the risk of breaking
     * all recurrences I'll just look for that duplicate.
     */
    String firstRecurrenceId = null;
    for (final Period p : rp.instances) {
        String dtval = p.getStart().toString();
        if (dateOnly) {
            dtval = dtval.substring(0, 8);
        }
        final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
        final DateTime edt = p.getEnd();
        if (!dateOnly && (stz != null)) {
            edt.setTimeZone(stz);
        }
        dtval = edt.toString();
        if (dateOnly) {
            dtval = dtval.substring(0, 8);
        }
        final BwDateTime rend = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
        final BwRecurrenceInstance ri = new BwRecurrenceInstance();
        ri.setDtstart(rstart);
        ri.setDtend(rend);
        ri.setRecurrenceId(ri.getDtstart().getDate());
        ri.setMaster(val);
        if (firstRecurrenceId == null) {
            firstRecurrenceId = ri.getRecurrenceId();
        } else if (firstRecurrenceId.equals(ri.getRecurrenceId())) {
            // Skip it
            if (debug) {
                debugMsg("Skipping duplicate recurid " + firstRecurrenceId);
            }
            continue;
        }
        if (recurids != null) {
            /* See if we have a recurrence */
            final String rid = ri.getRecurrenceId();
            final BwEventProxy ov = recurids.get(rid);
            if (ov != null) {
                if (debug) {
                    debugMsg("Add override with recurid " + rid);
                }
                setupDependentEntities(ov);
                addOverride(ov, ri);
                recurids.remove(rid);
            }
        }
        dao.save(ri);
        maxInstances--;
        if (maxInstances == 0) {
            // That's all you're getting from me
            break;
        }
    }
    if ((recurids != null) && (recurids.size() != 0)) {
        /* We removed all the valid overrides - we are left with those
       * with recurrence ids that don't match.
       */
        if (rollbackOnError) {
            throwException(CalFacadeException.invalidOverride);
        }
        uer.failedOverrides = recurids.values();
    }
    if (!getForRestore()) {
        notify(SysEvent.SysCode.ENTITY_ADDED, val, shared);
    }
    indexEntity(ei);
    stat(StatsEvent.createTime, startTime);
    return uer;
}
Also used : BwDateTime(org.bedework.calfacade.BwDateTime) CollectionInfo(org.bedework.calfacade.BwCalendar.CollectionInfo) Period(net.fortuna.ical4j.model.Period) BwEvent(org.bedework.calfacade.BwEvent) BwCalendar(org.bedework.calfacade.BwCalendar) BwEventProxy(org.bedework.calfacade.BwEventProxy) DateTime(net.fortuna.ical4j.model.DateTime) BwDateTime(org.bedework.calfacade.BwDateTime) BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) TimeZone(net.fortuna.ical4j.model.TimeZone) BwEventAnnotation(org.bedework.calfacade.BwEventAnnotation) RecurPeriods(org.bedework.icalendar.RecurUtil.RecurPeriods)

Example 9 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method removeInstance.

/* Remove instances identified by the Collection of recurrence ids
   */
private void removeInstance(final BwEvent master, final UpdateEventResult uc, final Collection<BwEventProxy> overrides, final String rid, final boolean shared) throws CalFacadeException {
    notifyInstanceChange(SysEvent.SysCode.ENTITY_DELETED, master, shared, rid);
    if (overrides != null) {
        for (final BwEventProxy pr : overrides) {
            if (pr.getRecurrenceId() == null) {
                throw new NullPointerException();
            }
            if (pr.getRecurrenceId().equals(rid)) {
                // This one is being deleted
                overrides.remove(pr);
                break;
            }
        }
    }
    final BwRecurrenceInstance inst = dao.getInstance(master, rid);
    if (inst != null) {
        dao.delete(inst);
        uc.addDeleted(inst);
    }
}
Also used : BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) BwEventProxy(org.bedework.calfacade.BwEventProxy)

Example 10 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method addInstances.

/* Add instances identified by the Collection of recurrence ids
   */
private void addInstances(final BwEvent master, final UpdateEventResult uc, final Collection<BwEventProxy> overrides, final Collection rids, final boolean shared) throws CalFacadeException {
    final Dur dur = new Dur(master.getDuration());
    for (final Object rid : rids) {
        final BwDateTime start = (BwDateTime) rid;
        final BwDateTime end = start.addDur(dur);
        final BwRecurrenceInstance ri = new BwRecurrenceInstance();
        ri.setDtstart(start);
        ri.setDtend(end);
        ri.setRecurrenceId(start.getDate());
        ri.setMaster(master);
        if (!Util.isEmpty(overrides)) {
            for (final BwEventProxy pxy : overrides) {
                final BwEventAnnotation ann = pxy.getRef();
                if (!ann.getRecurrenceId().equals(ri.getRecurrenceId())) {
                    continue;
                }
                // be safe
                ann.setRecurring(false);
                if (ann.getTombstoned() == null) {
                    // be safe
                    ann.setTombstoned(false);
                }
                if (!ann.unsaved()) {
                    updateProxy(new BwEventProxy(ann));
                } else {
                    dao.save(ann);
                }
                ri.setOverride(ann);
                break;
            }
        }
        dao.save(ri);
        notifyInstanceChange(SysEvent.SysCode.ENTITY_ADDED, master, shared, start.getDate());
        uc.addAdded(ri);
    }
}
Also used : Dur(net.fortuna.ical4j.model.Dur) BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) BwDateTime(org.bedework.calfacade.BwDateTime) BwEventAnnotation(org.bedework.calfacade.BwEventAnnotation) BwEventProxy(org.bedework.calfacade.BwEventProxy)

Aggregations

BwRecurrenceInstance (org.bedework.calfacade.BwRecurrenceInstance)12 BwDateTime (org.bedework.calfacade.BwDateTime)8 BwEvent (org.bedework.calfacade.BwEvent)7 BwEventAnnotation (org.bedework.calfacade.BwEventAnnotation)6 BwEventProxy (org.bedework.calfacade.BwEventProxy)5 Period (net.fortuna.ical4j.model.Period)3 CoreEventInfo (org.bedework.calcorei.CoreEventInfo)3 BwCalendar (org.bedework.calfacade.BwCalendar)3 RecurPeriods (org.bedework.icalendar.RecurUtil.RecurPeriods)3 TreeSet (java.util.TreeSet)2 Dur (net.fortuna.ical4j.model.Dur)2 CollectionInfo (org.bedework.calfacade.BwCalendar.CollectionInfo)2 CalFacadeException (org.bedework.calfacade.exc.CalFacadeException)2 EventInfo (org.bedework.calfacade.svc.EventInfo)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 DateTime (net.fortuna.ical4j.model.DateTime)1 TimeZone (net.fortuna.ical4j.model.TimeZone)1 CurrentAccess (org.bedework.access.Acl.CurrentAccess)1