use of org.bedework.calsvc.scheduling.SchedulingIntf in project bw-calendar-engine by Bedework.
the class Events method update.
@Override
public UpdateResult update(final EventInfo ei, final boolean noInvites, final String fromAttUri, final boolean alwaysWrite) throws CalFacadeException {
try {
final BwEvent event = ei.getEvent();
final UpdateResult updResult = ei.getUpdResult();
updateEntities(updResult, event);
final BwCalendar cal = validate(event, false, false, false);
adjustEntities(ei);
final RealiasResult raResp = reAlias(event);
if (raResp.getStatus() != ok) {
throw new CalFacadeException(CalFacadeException.badRequest, "Status: " + raResp.getStatus() + " message: " + raResp.getMessage());
}
boolean organizerSchedulingObject = false;
boolean attendeeSchedulingObject = false;
if (cal.getCollectionInfo().scheduling) {
organizerSchedulingObject = event.getOrganizerSchedulingObject();
attendeeSchedulingObject = event.getAttendeeSchedulingObject();
}
boolean schedulingObject = organizerSchedulingObject || attendeeSchedulingObject;
if (event.getSignificantChange() && schedulingObject) {
event.updateStag(getCurrentTimestamp());
}
boolean changed = alwaysWrite || checkChanges(ei, organizerSchedulingObject, attendeeSchedulingObject) || ei.getOverridesChanged();
boolean sequenceChange = ei.getUpdResult().sequenceChange;
/* TODO - this is wrong.
At the very least we should only reschedule the override that changed.
However adding an override looks like a change for all the fields
copied in. There should only be a change if the value is different
*/
boolean doReschedule = ei.getUpdResult().doReschedule;
if (ei.getNumOverrides() > 0) {
for (final EventInfo oei : ei.getOverrides()) {
setScheduleState(oei.getEvent(), false, false);
if (cal.getCollectionInfo().scheduling && oei.getEvent().getAttendeeSchedulingObject()) {
schedulingObject = true;
attendeeSchedulingObject = true;
// Shouldn't need to check organizer - it's set in the master even
// if suppressed.
}
if (checkChanges(oei, organizerSchedulingObject, attendeeSchedulingObject)) {
changed = true;
if (oei.getUpdResult().sequenceChange) {
sequenceChange = true;
}
}
if (schedulingObject) {
oei.getEvent().updateStag(getCurrentTimestamp());
}
doReschedule = doReschedule || oei.getUpdResult().doReschedule;
}
}
if (!changed) {
if (debug) {
trace("No changes to event: returning");
}
return ei.getUpdResult();
}
event.setDtstamps(getCurrentTimestamp());
if (organizerSchedulingObject && sequenceChange) {
event.setSequence(event.getSequence() + 1);
}
final UpdateEventResult uer = getCal().updateEvent(ei);
updResult.addedInstances = uer.added;
updResult.updatedInstances = uer.updated;
updResult.deletedInstances = uer.deleted;
updResult.fromAttUri = fromAttUri;
if (!noInvites && schedulingObject) {
if (organizerSchedulingObject) {
// Set RSVP on all attendees with PARTSTAT = NEEDS_ACTION
for (final BwAttendee att : event.getAttendees()) {
if (att.getPartstat().equals(IcalDefs.partstatValNeedsAction)) {
att.setRsvp(true);
}
}
}
boolean sendit = organizerSchedulingObject || updResult.reply;
if (!sendit) {
if (!Util.isEmpty(ei.getOverrides())) {
for (final EventInfo oei : ei.getOverrides()) {
if (oei.getUpdResult().reply) {
sendit = true;
break;
}
}
}
}
if (sendit) {
final SchedulingIntf sched = (SchedulingIntf) getSvc().getScheduler();
sched.implicitSchedule(ei, false);
/* We assume we don't need to update again to set attendee status
* Trying to do an update results in duplicate key errors.
*
* If it turns out the scgedule status is not getting persisted in the
* calendar entry then we need to find a way to set just that value in
* already persisted entity.
*/
}
}
return updResult;
} catch (final Throwable t) {
getSvc().rollbackTransaction();
if (t instanceof CalFacadeException) {
throw (CalFacadeException) t;
}
throw new CalFacadeException(t);
}
}
use of org.bedework.calsvc.scheduling.SchedulingIntf in project bw-calendar-engine by Bedework.
the class Events method add.
@Override
public UpdateResult add(final EventInfo ei, final boolean noInvites, final boolean schedulingInbox, final boolean autoCreateCollection, final boolean rollbackOnError) throws CalFacadeException {
try {
if (getPrincipalInfo().getSubscriptionsOnly()) {
throw new CalFacadeForbidden("User has read only access");
}
final UpdateResult updResult = ei.getUpdResult();
updResult.adding = true;
updResult.hasChanged = true;
final BwEvent event = ei.getEvent();
adjustEntities(ei);
final BwPreferences prefs = getSvc().getPrefsHandler().get();
if (prefs != null) {
final Collection<BwCategory> cats = getSvc().getCategoriesHandler().get(prefs.getDefaultCategoryUids());
for (final BwCategory cat : cats) {
event.addCategory(cat);
}
}
final RealiasResult raResp = reAlias(event);
if (raResp.getStatus() != ok) {
throw new CalFacadeException(CalFacadeException.badRequest, "Status: " + raResp.getStatus() + " message: " + raResp.getMessage());
}
// Or just validate?
assignGuid(event);
updateEntities(updResult, event);
BwCalendar cal = validate(event, true, schedulingInbox, autoCreateCollection);
BwEventProxy proxy = null;
BwEvent override = null;
if (event instanceof BwEventProxy) {
proxy = (BwEventProxy) event;
override = proxy.getRef();
setupSharableEntity(override, getPrincipal().getPrincipalRef());
} else {
setupSharableEntity(event, getPrincipal().getPrincipalRef());
if (ei.getNumContainedItems() > 0) {
for (final EventInfo aei : ei.getContainedItems()) {
final BwEvent av = aei.getEvent();
av.setParent(event);
setupSharableEntity(av, getPrincipal().getPrincipalRef());
}
}
}
final BwCalendar undereffedCal = cal;
if (cal.getInternalAlias()) {
/* Resolve the alias and put the event in it's proper place */
// XXX This is probably OK for non-public admin
final boolean setCats = getSvc().getPars().getPublicAdmin();
if (!setCats) {
cal = getCols().resolveAlias(cal, true, false);
} else {
while (true) {
final Set<BwCategory> cats = cal.getCategories();
for (final BwCategory cat : cats) {
event.addCategory(cat);
}
if (!cal.getInternalAlias()) {
break;
}
cal = getCols().resolveAlias(cal, false, false);
}
}
event.setColPath(cal.getPath());
}
if (!cal.getCalendarCollection()) {
throw new CalFacadeAccessException();
}
if (!event.getPublick() && Util.isEmpty(event.getAlarms())) {
setDefaultAlarms(ei, undereffedCal);
}
boolean schedulingObject = false;
if (cal.getCollectionInfo().scheduling && (event.getOrganizerSchedulingObject() || event.getAttendeeSchedulingObject())) {
schedulingObject = true;
}
final Integer maxAttendees = getSvc().getAuthProperties().getMaxAttendeesPerInstance();
if ((maxAttendees != null) && !Util.isEmpty(event.getAttendees()) && (event.getAttendees().size() > maxAttendees)) {
throw new CalFacadeException(CalFacadeException.schedulingTooManyAttendees);
}
event.setDtstamps(getCurrentTimestamp());
if (schedulingObject) {
event.updateStag(getCurrentTimestamp());
}
/* All Overrides go in same calendar and have same name */
final Collection<BwEventProxy> overrides = ei.getOverrideProxies();
if (overrides != null) {
for (final BwEventProxy ovei : overrides) {
setScheduleState(ovei, true, schedulingInbox);
if ((maxAttendees != null) && !Util.isEmpty(ovei.getAttendees()) && (ovei.getAttendees().size() > maxAttendees)) {
throw new CalFacadeException(CalFacadeException.schedulingTooManyAttendees);
}
ovei.setDtstamps(getCurrentTimestamp());
if (cal.getCollectionInfo().scheduling && (ovei.getOrganizerSchedulingObject() || ovei.getAttendeeSchedulingObject())) {
schedulingObject = true;
}
if (schedulingObject) {
ovei.updateStag(getCurrentTimestamp());
}
final BwEventAnnotation ann = ovei.getRef();
ann.setColPath(event.getColPath());
ann.setName(event.getName());
}
}
if (event.getOrganizerSchedulingObject()) {
// Set RSVP on all attendees with PARTSTAT = NEEDS_ACTION
for (final BwAttendee att : event.getAttendees()) {
if (att.getPartstat() == IcalDefs.partstatValNeedsAction) {
att.setRsvp(true);
}
}
}
UpdateEventResult uer = getCal().addEvent(ei, schedulingInbox, rollbackOnError);
if (ei.getNumContainedItems() > 0) {
for (final EventInfo oei : ei.getContainedItems()) {
oei.getEvent().setName(event.getName());
final UpdateEventResult auer = getCal().addEvent(oei, schedulingInbox, rollbackOnError);
if (auer.errorCode != null) {
// ?
}
}
}
updResult.failedOverrides = uer.failedOverrides;
if (!noInvites) {
if (event.getAttendeeSchedulingObject()) {
// Attendee replying?
updResult.reply = true;
}
if (cal.getCollectionInfo().scheduling && schedulingObject) {
final SchedulingIntf sched = (SchedulingIntf) getSvc().getScheduler();
sched.implicitSchedule(ei, false);
/* We assume we don't need to update again to set attendee status
* Trying to do an update results in duplicate key errors.
*
* If it turns out the scgedule status is not getting persisted in the
* calendar entry then we need to find a way to set just that value in
* already persisted entity.
*/
}
}
return updResult;
} catch (final Throwable t) {
if (debug) {
error(t);
}
getSvc().rollbackTransaction();
if (t instanceof CalFacadeException) {
throw (CalFacadeException) t;
}
throw new CalFacadeException(t);
}
}
use of org.bedework.calsvc.scheduling.SchedulingIntf in project bw-calendar-engine by Bedework.
the class InRequest method newAttendeeCopy.
/**
* Add the event to newCol from the incoming request
*
* @param svci
* @param newCol - path for new copy
* @param inEi
* @param attUri - our attendee uri
* @return event added or null if not added
* @throws CalFacadeException
*/
private EventInfo newAttendeeCopy(final CalSvcI svci, final String newCol, final EventInfo inEi, final String attUri) throws CalFacadeException {
SchedulingIntf sched = (SchedulingIntf) svci.getScheduler();
// Adding a copy
EventInfo calEi = sched.copyEventInfo(inEi, svci.getPrincipal());
BwEvent calEv = calEi.getEvent();
if (!initAttendeeCopy(svci, newCol, calEv, attUri)) {
return null;
}
if (calEi.getNumOverrides() == 0) {
return calEi;
}
for (EventInfo ei : calEi.getOverrides()) {
if (!initAttendeeCopy(svci, newCol, ei.getEvent(), attUri)) {
return null;
}
}
return calEi;
}
use of org.bedework.calsvc.scheduling.SchedulingIntf in project bw-calendar-engine by Bedework.
the class InRequest method process.
/**
* @param ei
* @return ScheduleResult
* @throws CalFacadeException
*/
@Override
public ProcessResult process(final EventInfo ei) throws CalFacadeException {
/* We are acting as an attendee getting a request from the organizer, either
* a first invitation or an update
*/
ProcessResult pr = new ProcessResult();
BwPreferences prefs = getSvc().getPrefsHandler().get();
BwEvent ev = ei.getEvent();
String owner = ev.getOwnerHref();
boolean schedAssistant = ev.isSchedulingAssistant();
if (debug) {
trace("InSchedule schedAssistant = " + schedAssistant);
}
/* First we save or update the event in the users default scheduling calendar
*/
SchedulingIntf sched = (SchedulingIntf) getSvc().getScheduler();
String uri = getSvc().getDirectories().principalToCaladdr(getSvc().getPrincipal());
String colPath = null;
EventInfo ourCopy = null;
boolean adding = false;
ev.setAttendeeSchedulingObject(true);
ev.setOrganizerSchedulingObject(false);
check: {
ourCopy = sched.getStoredMeeting(ev);
if (ourCopy != null) {
if (debug) {
trace("InSchedule update for " + owner);
}
colPath = ourCopy.getEvent().getColPath();
final boolean vpoll = ev.getEntityType() == IcalDefs.entityTypeVpoll;
if (vpoll) {
if (!updateAttendeePollCopy(ourCopy, ei, uri)) {
break check;
}
} else if (!updateAttendeeCopy(ourCopy, ei, uri)) {
break check;
}
pr.removeInboxEntry = !anySignificantChange(ourCopy);
} else {
/* New invitation - Save in default */
adding = true;
if (debug) {
trace("InSchedule add for " + owner);
}
String prefSched = getSvc().getCalendarsHandler().getPreferred(IcalDefs.entityTypeIcalNames[ev.getEntityType()]);
if (prefSched == null) {
// SCHED - status = no default collection
if (debug) {
trace("InSchedule - no default collection for " + owner);
}
// XXX set error code in request status
pr.removeInboxEntry = true;
return pr;
}
ourCopy = newAttendeeCopy(getSvc(), prefSched, ei, uri);
if (ourCopy == null) {
if (debug) {
trace("InSchedule - unable to add to calendar for " + owner);
}
// XXX set error code in request status
pr.removeInboxEntry = true;
return pr;
}
ev.addXproperty(new BwXproperty(BwXproperty.bedeworkSchedulingNew, null, "true"));
pr.removeInboxEntry = false;
}
}
if (schedAssistant) {
// Don't need the notification
pr.removeInboxEntry = true;
}
ev.addXproperty(new BwXproperty(BwXproperty.bedeworkSchedulingEntityPath, null, colPath));
/* We've saved it in the users calendar - now see if they want to auto
* respond.
*/
boolean noInvites = true;
boolean doAutoRespond = !pr.removeInboxEntry && !schedAssistant && prefs.getScheduleAutoRespond();
if (doAutoRespond) {
if (debug) {
trace("InSchedule - auto responding for " + owner);
}
noInvites = !autoRespond(getSvc(), ourCopy, ei, prefs.getScheduleDoubleBook(), uri);
}
if (adding) {
final String namePrefix = ourCopy.getEvent().getUid();
pr.sr.errorCode = sched.addEvent(ourCopy, namePrefix, BwCalendar.calTypeCalendarCollection, noInvites);
if (pr.sr.errorCode != null) {
if (debug) {
trace("Schedule - error " + pr.sr.errorCode + " adding event for " + owner);
}
return pr;
}
} else {
final UpdateResult ur = getSvc().getEventsHandler().update(ourCopy, noInvites, null);
if (debug) {
trace("Schedule - update result " + pr.sr + " for event" + ourCopy.getEvent());
}
if (ur.schedulingResult != null) {
pr.sr = ur.schedulingResult;
}
}
pr.attendeeAccepting = !Util.isEmpty(ev.getXproperties(BwXproperty.bedeworkSchedulingReplyUpdate));
return pr;
}
use of org.bedework.calsvc.scheduling.SchedulingIntf in project bw-calendar-engine by Bedework.
the class SchedAttendeeUpdate method attendeeRespond.
private ScheduleResult attendeeRespond(final EventInfo ei, final int method) throws CalFacadeException {
ScheduleResult sr = new ScheduleResult();
final BwEvent ev = ei.getEvent();
final SchedulingIntf sched = (SchedulingIntf) getSvc().getScheduler();
final String attUri = getSvc().getDirectories().principalToCaladdr(getSvc().getPrincipal());
check: {
/* Check that the current user is actually an attendee of the event.
* Note we may have a suppressed master and/or multiple overrides
*/
BwAttendee att = null;
if (!ev.getSuppressed()) {
att = ev.findAttendee(attUri);
if (att == null) {
sr.errorCode = CalFacadeException.schedulingNotAttendee;
break check;
}
}
if (ei.getNumOverrides() > 0) {
for (final EventInfo oei : ei.getOverrides()) {
att = oei.getEvent().findAttendee(attUri);
if (att == null) {
sr.errorCode = CalFacadeException.schedulingNotAttendee;
break check;
}
}
}
if (ev.getOriginator() == null) {
sr.errorCode = CalFacadeException.schedulingNoOriginator;
break check;
}
// EventInfo outEi = makeReplyEventInfo(ei, getUser().getPrincipalRef());
final EventInfo outEi = sched.copyEventInfo(ei, getPrincipal());
final BwEvent outEv = outEi.getEvent();
if (!Util.isEmpty(outEv.getRecipients())) {
outEv.getRecipients().clear();
}
if (!Util.isEmpty(outEv.getAttendees())) {
outEv.getAttendees().clear();
}
// XXX we should get a comment from non db field in event
// if (comment != null) {
// // Just add for the moment
// outEv.addComment(null, comment);
// }
outEv.addRecipient(outEv.getOrganizer().getOrganizerUri());
outEv.setOriginator(att.getAttendeeUri());
outEv.updateDtstamp();
outEv.getOrganizer().setDtstamp(outEv.getDtstamp());
final String delegate = att.getDelegatedTo();
if (delegate != null) {
/* RFC 2446 4.2.5 - Delegating an event
*
* When delegating an event request to another "Calendar User", the
* "Delegator" must both update the "Organizer" with a "REPLY" and send
* a request to the "Delegate". There is currently no protocol
* limitation to delegation depth. It is possible for the original
* delegate to delegate the meeting to someone else, and so on. When a
* request is delegated from one CUA to another there are a number of
* responsibilities required of the "Delegator". The "Delegator" MUST:
*
* . Send a "REPLY" to the "Organizer" with the following updates:
* . The "Delegator's" "ATTENDEE" property "partstat" parameter set
* to "delegated" and the "delegated-to" parameter is set to the
* address of the "Delegate"
* . Add an additional "ATTENDEE" property for the "Delegate" with
* the "delegated-from" property parameter set to the "Delegator"
* . Indicate whether they want to continue to receive updates when
* the "Organizer" sends out updated versions of the event.
* Setting the "rsvp" property parameter to "TRUE" will cause the
* updates to be sent, setting it to "FALSE" causes no further
* updates to be sent. Note that in either case, if the "Delegate"
* declines the invitation the "Delegator" will be notified.
* . The "Delegator" MUST also send a copy of the original "REQUEST"
* method to the "Delegate".
*/
// outEv is the reply
outEv.setScheduleMethod(Icalendar.methodTypeReply);
// Additional attendee
final BwAttendee delAtt = new BwAttendee();
delAtt.setAttendeeUri(delegate);
delAtt.setDelegatedFrom(att.getAttendeeUri());
delAtt.setPartstat(IcalDefs.partstatValNeedsAction);
delAtt.setRsvp(true);
delAtt.setRole(att.getRole());
outEv.addAttendee(delAtt);
// ei is 'original "REQUEST"'. */
final EventInfo delegateEi = sched.copyEventInfo(ei, getPrincipal());
final BwEvent delegateEv = delegateEi.getEvent();
delegateEv.addRecipient(delegate);
// Not in RFC
delegateEv.addAttendee((BwAttendee) delAtt.clone());
delegateEv.setScheduleMethod(Icalendar.methodTypeRequest);
att.setPartstat(IcalDefs.partstatValDelegated);
att.setRsvp(false);
att.setDelegatedTo(delegate);
// XXX Not sure if this is correct
sched.schedule(delegateEi, null, null, false);
} else if (method == Icalendar.methodTypeReply) {
// Only attendee should be us
ei.setOnlyAttendee(outEi, att.getAttendeeUri());
outEv.setScheduleMethod(Icalendar.methodTypeReply);
} else if (method == Icalendar.methodTypeCounter) {
// Only attendee should be us
ei.setOnlyAttendee(outEi, att.getAttendeeUri());
/* Not sure how much we can change - at least times of the meeting.
*/
outEv.setScheduleMethod(Icalendar.methodTypeCounter);
} else {
throw new RuntimeException("Never get here");
}
outEv.addRequestStatus(new BwRequestStatus(IcalDefs.requestStatusSuccess.getCode(), IcalDefs.requestStatusSuccess.getDescription()));
sr = sched.scheduleResponse(outEi);
outEv.setScheduleState(BwEvent.scheduleStateProcessed);
ev.getOrganizer().setScheduleStatus(IcalDefs.deliveryStatusDelivered);
}
return sr;
}
Aggregations